现象:
发送文件,发送端循环读取一片组装成我自己定义的数据包(有包头,长度,压缩数据 等信息)发送出去。
接收端在OnRead事件中读取。
1.读取到大于一个我自己的数据包就去拆分数据包(可能接收到多个数据包粘连在一起的情况),可能是>=1个
2.拆分出来m个数据包后循环解压数据。
3.将解压出的真实数据传入一个外部回调函数,
4.外部回调函数将数据写到文件里。-----
问题出现:
发送端,我在循环中每个数据包里加了个序号:
接收时,将序号显示出来时,是乱序的。比如:
------------------------
序号 本次数据包个数
1 4
2 4
5 1
6 1
3 4
4 4
------------------
数据包顺序不正确了。感觉是在接收到数据后,拆分、解压、响应回调相对比较慢,在此时又响应了一次OnRead事件,而在第一次OnRead事件中,收到了多个,还没来的急全部写到文件中,第二次只收到1个数据包,就写到文件中了。导致数据顺序不对。
我读了一下delphi的源码,使用的是WSAAsyncSelect(FSocket, Wnd, Msg, Longint(Byte(FAsyncStyles)))模式,也就是从Wnd窗口消息中获得有数据到来,而消息是异步的,相当于postmessage发出来的一样。
我之前的数据没处理完成,第二次消息又来了,第二次消息中收到的数据比第一次的少,先完成,导致数据顺序不正确。
不知道我的分析对不对?目前不知道如何解决这个问题,请大家多多帮助,指点,在此非常感谢!
发送文件,发送端循环读取一片组装成我自己定义的数据包(有包头,长度,压缩数据 等信息)发送出去。
接收端在OnRead事件中读取。
1.读取到大于一个我自己的数据包就去拆分数据包(可能接收到多个数据包粘连在一起的情况),可能是>=1个
2.拆分出来m个数据包后循环解压数据。
3.将解压出的真实数据传入一个外部回调函数,
4.外部回调函数将数据写到文件里。-----
问题出现:
发送端,我在循环中每个数据包里加了个序号:
接收时,将序号显示出来时,是乱序的。比如:
------------------------
序号 本次数据包个数
1 4
2 4
5 1
6 1
3 4
4 4
------------------
数据包顺序不正确了。感觉是在接收到数据后,拆分、解压、响应回调相对比较慢,在此时又响应了一次OnRead事件,而在第一次OnRead事件中,收到了多个,还没来的急全部写到文件中,第二次只收到1个数据包,就写到文件中了。导致数据顺序不对。
我读了一下delphi的源码,使用的是WSAAsyncSelect(FSocket, Wnd, Msg, Longint(Byte(FAsyncStyles)))模式,也就是从Wnd窗口消息中获得有数据到来,而消息是异步的,相当于postmessage发出来的一样。
我之前的数据没处理完成,第二次消息又来了,第二次消息中收到的数据比第一次的少,先完成,导致数据顺序不正确。
不知道我的分析对不对?目前不知道如何解决这个问题,请大家多多帮助,指点,在此非常感谢!
TClientSocket和TServerSocket组件来写,自己直接用api来写,如果数据包快的话用iocp试试.
数据收到先缓存一些数据,再一次性写.
我现在很多程序中都用到了这个类, 并且不是服务器才有这个问题,只要发送方,循环发送,接收端有就有可能粘包,一粘包解析就就慢了,慢了就会再次接收到onread事件,顺序就乱了。
---------------------------------------
procedure TADLTcpClient.Read(Sender: TObject; Socket: TCustomWinSocket); //响应OnRead事件
begin
ReceviceCommand(Socket);
end;
----------------------------------------
procedure TADLTcpClient.ReceviceCommand(Socket: TCustomWinSocket);
var
NetCommand: TADLNetCommand;
RecLen: Integer;
i, PackageCount: Integer;
pData: Pointer;
NetCommandList:TList;
begin NetCommand := nil; //FNetInOutPackage类是用来专门接收、发送、加压、解压数据的,传了socket进去,服务器端和客户端都用这个类。
RecLen := FNetInOutPackage.ReciveNetPackage(Socket);
if RecLen <= 0 then
Exit;
//定义了一个指针,用来保存半截包
pData := nil;
//折分数据包,得到包的个数,如果有半包,返回pData不为nil
PackageCount := FNetInOutPackage.GetNetPackageCount(pData);
//将半截包,保存到Socket.Data 指针中,
Socket.Data := pData; //NetCommandList 用来保存解压还原后的数据数据,每一个item是一个类(我发送过来的数据会还原成一个类)
NetCommandList := TList.Create;
//循环将PackageCount个包,解压,还原
for i := 0 to PackageCount - 1 do
begin
NetCommand := FNetInOutPackage.OutOfPackage(i); // 这里解压、还原成一个类对象
//还原出错,或解压出错为nil,
if NetCommand = nil then
begin
Socket.Close;
NetCommandList.Free;
Exit;
end;
NetCommandList.Add(NetCommand);//将返回的对象指针放到list, 还原完了再同时响应外部回调函数
end; //这里清空FNetInOutPackage内部的拆分数据包链表。上面的循环就是循环的这个链表中的数据
FNetInOutPackage.ClearPackageList;
//下面响应回调函数。
if Assigned(FOnReceviceCommand) then
begin
for i := 0 to NetCommandList.Count - 1 do
begin
NetCommand := TADLNetCommand(NetCommandList.Items[i]);
NetCommand.Tag := NetCommandList.Count;
//if NetCommandList.Count > 1 then
// MessageBox(Application.Handle, pchar(inttostr(Integer(@Socket))),'',MB_OK);
FOnReceviceCommand(Socket, FNetInOutPackage, NetCommand);
end;
end;
NetCommandList.Free;
end;
这下问题找到了....
Application.pocessmessage中是执行的peekmessage,TranslateMessage,DispatchMessage 将消息队列中的消息又分派出来,导致响应网络接收消息。。使用数据顺序不正确!!