delphi中clientsocket控件通讯,读取数据丢包问题?
用clientsocket控件进行通讯,读取数据处理,当对方发送很快时,就发现多包数据赌在一起了,检验没通过,请教各位如何处理?
[解决办法]
参考下面贴子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;
原理:先取包,然后校验包头尾和长度,合法就继续处理,不合法则不处理。
这种方式不怕粘包,只怕断包,不过要判断断包也简单,方法如下:
收到包后立即校验并将包分成一个一个的,存到临时数据里,如果最后一个包校验未通过,也就是说最后一个包如果是断包,则保存起来,
下次收到的包放在这个断包后面一起校验就行了(可以用反向搜索字符串的方法快速找出最后一个包,并判断出是否是断包)。