delphi中clientsocket控件通讯,读取数据丢包问题? 用clientsocket控件进行通讯,读取数据处理,当对方发送很快时,就发现多包数据赌在一起了,检验没通过,请教各位如何处理? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 参考下面贴子6楼的回复http://topic.csdn.net/u/20081114/11/091305bd-24cf-4c5c-9083-3993e4d98eae.html 可能是检验机制不太好,可以试试加头尾,和包长度,例如:#<长度><命令ID>[内容]*type PPacketHead = ^TPacketHead; TPacketHead = packed record Size: Word; CmdID: Byte; end; PPacketData = ^TPacketData; TPacketData = packed record Packet: TPacketHead; Socket: TCustomWinSocket; PData: Pointer; PSize: Word; end;{实现部分}function IncPointer(PP: Pointer; Size: Integer = 1): Pointer; inline;var P: PAnsiChar;begin P := PAnsiChar(PP); Inc(P, Size); Result := P;end;function IsTail(PP: Pointer; Size: Word): Boolean; inline;var P: PAnsiChar;begin P := PAnsiChar(PP); Inc(P, Size); Result := P^ = '*';end;procedure OnRecvSocketEvent(Socket: TCustomWinSocket; PData: Pointer; Size: Integer);var PB, PH: PAnsiChar; P: PPacketHead; PD: TPacketData; K: Integer;begin inherited; K := 0; PB := PData; while K < Size do begin PH := StrPos(PB, '#'); //每个数据包是#开头*结尾 if (PH <> nil) then begin if (K < Size) then begin P := IncPointer(PH); if (P^.Size > 0) and IsTail(PH, P^.Size + 1) then begin//处理这个包 PD.Packet := P^; PD.Socket := Socket; PD.PData := IncPointer(P, SizeOf(TPacketHead)); PD.PSize := P^.Size - SizeOf(TPacketHead); DoParse(PD);//自己按需要实现 K := K + P^.Size + 2; //头尾长度=2 PB := IncPointer(PB, K); end else PB := IncPointer(PB); end else PB := IncPointer(PB); end else Break; end;end;procedure OnRead(Sender: TObject; Socket: TCustomWinSocket);var Size: Integer; PData: Pointer;begin Size := Socket.ReceiveLength; if Size > 0 then try GetMem(PData, Size); Socket.ReceiveBuf(PData^, Size); OnRecvSocketEvent(Socket, PData, Size); finally FreeMem(PData); end;end; 原理:先取包,然后校验包头尾和长度,合法就继续处理,不合法则不处理。这种方式不怕粘包,只怕断包,不过要判断断包也简单,方法如下:收到包后立即校验并将包分成一个一个的,存到临时数据里,如果最后一个包校验未通过,也就是说最后一个包如果是断包,则保存起来,下次收到的包放在这个断包后面一起校验就行了(可以用反向搜索字符串的方法快速找出最后一个包,并判断出是否是断包)。 Delphi 执行SQL,绑定变量,丢失参数数据问题 Delphi+OpenGL怎样输出汉字 C++/C实现的功能DELPHI也可以实现到吗? 关于用注册表修改IP的问题! 一小问题,大家看看,见者有份 我要作个消费型磁卡程序,不知如何下手 如何在win98和win2000下分别实现重新启动的功能 想用FastReport一份报表中打印两个表格,来源于两个数据表,并在最后一行进行合计 DBGrid的颜色问题 fastreport 40 打印问题(发货单内容重复打印问题) 没有注册类别 idftp使用代理上传文件出现 socket 10060 错误
http://topic.csdn.net/u/20081114/11/091305bd-24cf-4c5c-9083-3993e4d98eae.html
#<长度><命令ID>[内容]*
type
PPacketHead = ^TPacketHead;
TPacketHead = packed record
Size: Word;
CmdID: Byte;
end; PPacketData = ^TPacketData;
TPacketData = packed record
Packet: TPacketHead;
Socket: TCustomWinSocket;
PData: Pointer;
PSize: Word;
end;
{实现部分}function IncPointer(PP: Pointer; Size: Integer = 1): Pointer; inline;
var
P: PAnsiChar;
begin
P := PAnsiChar(PP);
Inc(P, Size);
Result := P;
end;function IsTail(PP: Pointer; Size: Word): Boolean; inline;
var
P: PAnsiChar;
begin
P := PAnsiChar(PP);
Inc(P, Size);
Result := P^ = '*';
end;procedure OnRecvSocketEvent(Socket: TCustomWinSocket;
PData: Pointer; Size: Integer);
var
PB, PH: PAnsiChar;
P: PPacketHead;
PD: TPacketData;
K: Integer;
begin
inherited;
K := 0;
PB := PData;
while K < Size do begin
PH := StrPos(PB, '#'); //每个数据包是#开头*结尾
if (PH <> nil) then begin
if (K < Size) then begin
P := IncPointer(PH);
if (P^.Size > 0) and IsTail(PH, P^.Size + 1) then begin//处理这个包
PD.Packet := P^;
PD.Socket := Socket;
PD.PData := IncPointer(P, SizeOf(TPacketHead));
PD.PSize := P^.Size - SizeOf(TPacketHead);
DoParse(PD);//自己按需要实现
K := K + P^.Size + 2; //头尾长度=2
PB := IncPointer(PB, K);
end else
PB := IncPointer(PB);
end else
PB := IncPointer(PB);
end else Break;
end;
end;procedure OnRead(Sender: TObject; Socket: TCustomWinSocket);
var
Size: Integer;
PData: Pointer;
begin
Size := Socket.ReceiveLength;
if Size > 0 then try
GetMem(PData, Size);
Socket.ReceiveBuf(PData^, Size);
OnRecvSocketEvent(Socket, PData, Size);
finally
FreeMem(PData);
end;
end;
原理:先取包,然后校验包头尾和长度,合法就继续处理,不合法则不处理。
这种方式不怕粘包,只怕断包,不过要判断断包也简单,方法如下:
收到包后立即校验并将包分成一个一个的,存到临时数据里,如果最后一个包校验未通过,也就是说最后一个包如果是断包,则保存起来,
下次收到的包放在这个断包后面一起校验就行了(可以用反向搜索字符串的方法快速找出最后一个包,并判断出是否是断包)。