首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

急救:Delphi中IdUDPServer局域网内严重丢包的有关问题

2013-07-08 
急救:Delphi中IdUDPServer局域网内严重丢包的问题本帖最后由 zhangdaodong 于 2013-06-24 13:06:06 编辑本

急救:Delphi中IdUDPServer局域网内严重丢包的问题
本帖最后由 zhangdaodong 于 2013-06-24 13:06:06 编辑 本人想写一个局域网监控程序,有发消息,屏幕截图等。接收代码如下:

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  AData: array of Byte; ABinding: TIdSocketHandle);
var
  a:TMemoryStream;
  Command:TCommand;         //这是我自己定义的一个record
begin
  a := TMemoryStream.Create;
  a.WriteBuffer(AData[0],Length(AData));
  a.Position := 0;
  a.Read(Command,SizeOf(Command));
  FreeAndNil(a);
  ExcuteCommand(Command);   //通过函数处理接收到的record包
end;


record原型如下:
TCommand = record
  CommandType    : TOP;   //这中我定义的一个操作枚举类型
  CommandText    : string;
  Timeout        : Integer;
  FileStream     : TMemoryStream;  //这里面主要是存放截的图,大小不会超过3MB
  FormIP         : string;
  ToIP           : string;
end;

现在是这么个情况,给本机发送文本和截屏都很正常,给局域网别的机子发送文本正常,截图没反应,我猜可能是含图片的record比较大,发送过程中丢包了。请问大神们,我的IdUDPServer1UDPRead事件应该如何优化?最好能带点代码,我对网络这方面不太熟悉,谢谢了。
[解决办法]
引用:
Quote: 引用:

楼上已经说了,你传递过去的都是4个字节的指针而已……
对于字符串,你可以像楼上那样声明为固定长度的

但是对于你那个截图数据,长度是不固定的

所以建议你还是根据自己的需求规范一下包的格式……

还有,record应该声明为packed record  ,这样在内存中才是连续排放的
aqtata兄,请教一下,我不想传指针,直接传数据应该怎么办?但是文本内容别的电脑能收到,就是图像收不到,我改成了packed record也一样,实在没办法了,idUDPServer的BufferSize我设置得够大,应该不需要续传的。



随手给你写了一个简单的演示


TTOP = (one, two);

  TCommand = packed record
    PackageSize: DWORD;        // 整个包的大小,占4字节
    CommandType: TTOP;         // 枚举类型,可以,因为其实质就是Byte类型。占1字节


    Command: string[9];       // 命令行文本,占10字节。string的第1个字节用来描述长度,可用字符为9 byte
    PicSize: DWORD;            // 图片Size,占4字节
  end;


// 调用

var
  Value: TCommand;
  PicBuf: TBytesStream;
  PicData: array of Byte;
  SendBuf: TMemoryStream;
begin
  Buffer.CommandType := two;
  Buffer.Command := 'Hello';

  // 模拟一个图片数据,为了方便说明,假设图片只有5字节
  SetLength(PicData, 5);
  PicData[0] := $11;
  PicData[1] := $22;
  PicData[2] := $33;
  PicData[3] := $44;
  PicData[4] := $55;
  Buffer.PicSize := Length(PicData);
  Buffer.PackageSize := SizeOf(Buffer) + Length(PicData);   // 这里包的总长度为19

  // 将要发送的数据写入缓冲区
  SendBuf := TMemoryStream.Create;
  SendBuf.WriteBuffer(Buffer, SizeOf(Buffer));
  SendBuf.WriteBuffer(PicData[0], Length(PicData));
  SendBuf.Free;
end;



最后SendBuf的内存区域如图

急救:Delphi中IdUDPServer局域网内严重丢包的有关问题

开始的18 00 00 00 就是整个包的长度,这样能让接收方知道一个包到底有多长
接着的 01 是枚举类型,再接着的 05 就是string的长度
包末尾的 11 22 33 44 55 就是图片数据了,在此前的05 00 00 00就是图片数据的长度

这样,一个完整的包就OK了,接收方根据包提供的长度等信息读出数据

当然在实际运用中,你图片的数据可能是很大的,会有分包的情况
不是你设个100MB,就真的能一次发个100MB的包过去

而且UDP是可能会乱序的,可能你发的包,图片数据先到了,包头后来才到……

传输文件,建议用TCP,因为你这里要传输文件,所以要考虑分包的情况
[解决办法]
UDP包的大小得合理,太大肯定收不到,可以把图切成小块发,附带小块的位置
[解决办法]
不管什么方式,数据包大小都要合适,不要太大,否则存在分包的情况,这样你接收的数据可能不连续。。。

热点排行