-
Доброго времени суток. И снова я задам вопрос относительно UDP. Вот набросал Клиент и сервер на основе IdUDP. Клиент:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdUDPServer, XPMan, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, StdCtrls, IdSocketHandle,Jpeg, ExtCtrls;
type
TForm1 = class(TForm)
IdUDPClient1: TIdUDPClient;
Button1: TButton;
Image1: TImage;
Memo: TMemo;
procedure Button1Click(Sender: TObject);
procedure GrabScreen();
procedure FormCreate(Sender: TObject);
private
public
end;
var
Form1: TForm1;
Bitmap:TBitmap;
Jpeg:TJpegImage;
packNUM:integer;
implementation
procedure TForm1.GrabScreen();
var
DC : HDC;
bmp : TBitmap;
jpgImg: TJPEGImage;
Stream:TMemoryStream;
size:integer;
Buf:array[0..1024] of byte;
begin
Stream:=TMemoryStream.Create;
bmp := TBitmap.Create;
jpgImg := TJPEGImage.Create;
bmp.Height := Screen.Height;
bmp.Width := Screen.Width;
DC := GetDC(0);
bitblt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY);
ReleaseDC(0, DC);
jpgImg.Assign(bmp);
jpgImg.CompressionQuality:=100;
jpgImg.SaveToStream(Stream);
Stream.Position:=0;
size:=Stream.Size;
IdUDPClient1.Send('text'+IntToStr(Size));
packNUM:=0;
while Stream.Position<Stream.Size do
begin
packNUM:=packNUM+1;
size:=Stream.Read(Buf,SizeOf(Buf));
IdUDPClient1.SendBuffer(Buf,size);
Memo.Lines.Add(IntToStr(Stream.Position)+' < '+IntToStr(Stream.Size)+' пакет № '+IntToStr(packNUM));
end;
bmp.Assign(jpgImg);
jpgImg.Free;
Form1.Image1.Picture.Bitmap.Assign(bmp);
bmp.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
GrabScreen();
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Bitmap:=TBitmap.Create;
Jpeg:=TJpegImage.Create;
end;
end.
Сервер
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Forms,
ExtCtrls, StdCtrls, ScktComp, Controls,dialogs, ComCtrls,
IdUDPServer, XPMan, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, IdSocketHandle, math, Jpeg;
type
TForm1 = class(TForm)
IdUDPServer1: TIdUDPServer;
Memo: TMemo;
Image1: TImage;
Button1: TButton;
procedure IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
toread:integer;
MainSize:integer;
Size:integer;
proverka:integer;
StrStream : TStringStream;
MemStream : TMemoryStream;
packNUM:integer;
implementation
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
Buf:array[0..1023] of byte;
Jpeg:TJpegImage;
Bitmap:TBitmap;
begin
if AData.Size<=10 then
begin
packNUM:=0;
StrStream:=TStringStream.Create('');
StrStream.CopyFrom(AData, AData.Size);
Memo.Lines.Add(ABinding.PeerIP+': '+copy(StrStream.DataString,5,length(StrStream.DataString)));
MainSize:=StrToInt(copy(StrStream.DataString,5,length(StrStream.DataString)));
StrStream.Free;
MemStream:= TMemoryStream.Create;
MemStream.Size:=MainSize;
MemStream.Position:=0;
ToRead:=MemStream.Size-MemStream.Position;
ToRead:=Min(ToRead,AData.size);
end else
begin
if (ToRead>0) then
begin
packNUM:=packNUM+1;
Size:=Adata.Size;
if Size<0 then exit;
MemStream.WriteBuffer(Adata,Size);
ToRead:=MemStream.Size-MemStream.Position;
ToRead:=Min(ToRead,Adata.Size);
Memo.Lines.Add(IntToStr(Adata.Size) + ' пакет № '+IntToStr(packNUM));
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Jpeg:TJpegImage;
Bitmap:TBitmap;
begin
MemStream.Position:=0;
Jpeg:=TJpegImage.Create;
Bitmap:=TBitmap.Create;
try
Jpeg.LoadFromStream(MemStream);
Jpeg.SaveToFile('C:\Screenshot.jpg');
Bitmap.Assign(Jpeg);
finally
Form1.Image1.Picture.Bitmap.Assign(Bitmap);
Jpeg.Free;
Bitmap.Free;
end;
end;
end.
Клиент отсылает изображение на сервер, послав предварительно размер изображения. Компоненты Memo я добавил просто для отслеживания отосланных и принятых пакетов и их размеров. Все отсылается и вроде даже доходит, при нажатии на кнопку принятое изображение должно поместиться в Jpeg, но выдает ошибку Jpeg 53 (неверный формат). возможно я не вижу банальной ошибки...
-
зачем это MemStream.Size:=MainSize;?
а вот это хрень полная Memo.Lines.Add(ABinding.PeerIP+': '+copy(StrStream.DataString,5,length(StrStream.DataString)));
и Memo нельзя использовать в IdUDPServer1UDPRead
-
MemStream.Size:=MainSize; - лишняя строчка, забыл удалить. Memo это так для себя, его отсутствие не уберет проблему.
-
Большая часть взята из программы господина Slym'а только переделана под UDP, возможно я где то накосячил
-
> Troop (27.03.2011 17:30:02) [2]
Сколько еще строчек, которые ты забыл и мы про это даже не догадываемся?
-
Не надо нам гнать пургу, неизвестно, что в ответ тоже получишь пургу, ты публикуй только тот код, что у тебя есть, без какой либо отсебятины.
-
Я и опубликовал. Размер отсылаемого потока, совпадает с размером полученного, т.е. все доходит, но в Jpeg вогнать не получается
-
> Troop (27.03.2011 18:51:06) [6]
Ты опубликовал совсем другой код, сам же подтвердил это. Так ты каши не сваришь.
-
http://pda.delphimaster.net/?id=1227604925&n=4&p=1Тут изначальный код, используются компоненты ClientSocket и ServerSocket, я написал программу с нуля, просто принцип разбиения и передачи от туда (хотя он везде по существу одинаковый). Там онлайн передача, я же пока пытаюсь передать только единичное изображение рабочего стола. Вроде как все передает, но не тут то было.
-
> т.е. все доходит UDP это такая странная штука, что может не только не доходить, но и доходить не по порядку. и это вполне нормально. т.е. пропуски/порядок это все ложится на "совесть" программиста.
и кстати + > if AData.Size<=10 then а где гарантии, что размер данных всегда больше 10? особенно последний кусок.
++ размер буфера в UDP по умолчанию 8кб (в компоненте стоит), и насколько помню есть условия когда в принципе меньше не посылается, даже если посыл в 1 байт... а у тебя выбран буфер = 1кб + 1б. странно. (ну хотя бы круглую цифру... а то часть системного всегда будет пустой, хорошо если он всего 16 байт... но все же)
-
MemStream.Size:=MainSize; В этой строчки я задаю размер потока на прием (Предварительно на клиенте перед посылкой изображения отсылается размер потока)
-
if AData.Size<=10 да насчет этого я знаю, но обычно последний покет не меньше 500, хотя это легко исправить просто поставить boolean выражение, например if first_=true then , я пока рассматриваю отсыл только одного изображения.
Просто понять не могу в чем ошибка, знаю что UDP не надежен. Но как то писал отсыл файла через udp использую TFileStream, там кол-во пакетов доходило до несколько десятков тысяч, и в конечном счете файл доходил и открывался, а тут тоже вроде изображение доходит, но нечетабельно о_О
-
> Просто понять не могу в чем ошибка это то как раз элементарно... в разных данных там и здесь. очень просто можно убедится... вот вместо этого Jpeg.SaveToFile('C:\Screenshot.jpg'); сделать MemStream.Position:= 0; MemStream.SaveToFile('C:\ScreenServ.jpg');
и в клиенте jpgImg.SaveToStream(Stream); Stream.SaveToFile('C:\ScreenClient.jpg'); а после сравнить, можно побайтно... (есть проги) т.е. то что передаешь, в самом начале, с тем что принято, в самом конце. уверен будет разница.
> а тут тоже вроде изображение доходит комп не терпит слов "вроде". должно быть "точно" вплоть до последнего байта.
-
так делать не надо MemStream.Size:=MainSize;
-
Без MemStream.Size:=MainSize; тоже самое
-
Вот переписал немного, теперь на клиенте и на сервере стоит компонент TidUDPServer, и шлется уведомление о том, что пакет доставлен, пока пакет не дойдет, другие отсылаться не будут, т.е. все пакеты доставляются по порядку, НО ошибка 53 все равно осталась =(клиент
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdUDPServer, XPMan, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, StdCtrls, IdSocketHandle,Jpeg, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
Memo: TMemo;
IdUDPClient1: TIdUDPServer;
procedure Button1Click(Sender: TObject);
procedure GrabScreen();
procedure FormCreate(Sender: TObject);
procedure IdUDPClient1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
private
public
end;
var
Form1: TForm1;
get_accept: boolean = false;
Bitmap:TBitmap;
Jpeg:TJpegImage;
packNUM:integer;
implementation
procedure TForm1.GrabScreen();
var
DC : HDC;
bmp : TBitmap;
jpgImg: TJPEGImage;
Stream:TMemoryStream;
size:integer;
Buf:array[0..1024] of byte;
begin
Stream:=TMemoryStream.Create;
bmp := TBitmap.Create;
jpgImg := TJPEGImage.Create;
bmp.Height := Screen.Height;
bmp.Width := Screen.Width;
DC := GetDC(0);
bitblt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY);
ReleaseDC(0, DC);
jpgImg.Assign(bmp);
jpgImg.CompressionQuality:=100;
jpgImg.SaveToStream(Stream);
Stream.Position:=0;
size:=Stream.Size;
IdUDPClient1.Send('localhost',1151,'text'+IntToStr(Size));
packNUM:=0;
while Stream.Position<Stream.Size do
begin
packNUM:=packNUM+1;
size:=Stream.Read(Buf,SizeOf(Buf));
IdUDPClient1.SendBuffer('localhost',1151,Buf,size);
while get_accept=false do Application.ProcessMessages;
get_accept:=false;
Memo.Lines.Add(IntToStr(Stream.Position)+' < '+IntToStr(Stream.Size)+' пакет № '+IntToStr(packNUM));
end;
bmp.Assign(jpgImg);
jpgImg.Free;
Form1.Image1.Picture.Bitmap.Assign(bmp);
bmp.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
GrabScreen();
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Bitmap:=TBitmap.Create;
Jpeg:=TJpegImage.Create;
end;
procedure TForm1.IdUDPClient1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
begin
get_accept:=true;
end;
end.
Сервер
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Forms,
ExtCtrls, StdCtrls, ScktComp, Controls,dialogs, ComCtrls,
IdUDPServer, XPMan, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, IdSocketHandle, math, Jpeg;
type
TForm1 = class(TForm)
IdUDPServer1: TIdUDPServer;
Memo: TMemo;
Image1: TImage;
Button1: TButton;
Label1: TLabel;
procedure IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
toread:integer;
MainSize:integer;
Size:integer;
proverka:integer;
StrStream : TStringStream;
MemStream : TMemoryStream;
packNUM:integer;
SStream:TStream;
implementation
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
Buf:array[0..1023] of byte;
Jpeg:TJpegImage;
Bitmap:TBitmap;
begin
if AData.Size<=10 then
begin
packNUM:=0;
StrStream:=TStringStream.Create('');
StrStream.CopyFrom(AData, AData.Size);
MainSize:=StrToInt(copy(StrStream.DataString,5,length(StrStream.DataString)));
StrStream.Free;
MemStream:= TMemoryStream.Create;
MemStream.Size:=MainSize;
MemStream.Position:=0;
ToRead:=MemStream.Size-MemStream.Position;
ToRead:=Min(ToRead,AData.size);
end else
begin
packNUM:=packNUM+1;
Size:=Adata.Size;
if Size<0 then exit;
MemStream.WriteBuffer(Adata,Size);
ToRead:=MemStream.Size-MemStream.Position;
ToRead:=Min(ToRead,Adata.Size);
Memo.Lines.Add(IntToStr(MemStream.Position));
idUDPServer1.Send('localhost',1152,'accept');
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Jpeg:TJpegImage;
Bitmap:TBitmap;
begin
MemStream.Position:=0;
Jpeg:=TJpegImage.Create;
Bitmap:=TBitmap.Create;
SStream:=TStream.Create;
SStream:=MemStream;
try
Jpeg.CompressionQuality:=100;
label1.Caption:=IntToStr(MemStream.Position);
Jpeg.LoadFromStream(SStream);
Jpeg.SaveToFile('C:\Screenshot.jpg');
Bitmap.Assign(Jpeg);
finally
Form1.Image1.Picture.Bitmap.Assign(Bitmap);
Jpeg.Free;
Bitmap.Free;
end;
end;
end.
-
> НО ошибка 53 все равно осталась =( сравни данные "до" и "после", как в [12], они все еще НЕ совпадают...
p.s. на "кошках", что ли, бы потренировался... ну там текст из мемо в мемо пересылать... для потоков все одно, а намного виднее.
-
SStream:=TStream.Create; не нужно
Вообще с таким подходом к написанию кода странно, что у вас вообще хоть что-то работает. Очень сложно понять порядок передачи. Почему вы размер передаёте строкой? При чтении строки вполне может попасть пакет с изображением. Сохраните полученные данные в файл, чтобы сравнить с отправленными данными, строить здесь предположения очень сложно - ошибок много.
-
Это тоже для проверки создавалось =) можно убрать.
P.S. Ошибка решена, и она была очень глупой =). Нельзя было считывать напрямую из AData в поток, необходимо было с начало из AData считать в буффер (переменная Buf (размер на сервере надо изменить 0..1024)), а потом уже записать буффер в поток MemStream.
-
> Нельзя было считывать напрямую из AData в поток чушь. всегда так делал, ошибок, чтобы чего то неверно/криво передавалось не было.
> размер на сервере надо изменить 0..1024 а вот это верно. еще в [9] писал про странный "не круглый" размер буфера, на клиенте, вот ты там где то и путал, "откусывал" лишний байт видать. опять выбрал "не круглый"... но хоть одинаковый с клиентом.
|