天天看点

Delphi中关于TCP通讯,Indy粘数据包问题

发送端创建一个发送缓冲区,用 AddSendBuffer(AData:Pointer;ALen:Integer) 的方式将用户数据包加入到缓冲区.用另一个线程,从缓冲区的另一头取定长,比如说是 1024字节点长度的数据,加上包头形成一个发送数据包。

接收端也是创建一个接收缓冲区,将收到的每个发送数据包中的用户数据都按顺序放在缓冲区中。一个线程根据数据内容来确定是否接收完成一个用户数据包。完成后就给上层应用程序发一个消息。应用程序取到数据后将缓冲区中的对应数据删除。

Delphi中关于TCP通讯,Indy粘数据包问题

缓冲区中数据头的位置 画错了,应该在绿色的后面。在要加数据就加到绿色的后面,如果缓冲区满了,就从头开始,如果前面也没有空位了,就将缓冲区扩大,或暂停向缓冲区中加数据。

上面是发送缓冲区,里面的每个颜色是用户数据包。

发送线程只按固定的大小A 从缓冲区中取数据,加上顺序号和数据大小A(如果最后缓冲区数据大小比A小,则保存实际的数据大小),形成发送数据包。

接收端收到数据后,检查收到的数据中有多少个发送数据包,将数据包中的数据按顺序放在接收缓冲区中,如果发送数据包让截断了,则等一下个接收事件中取得后面的内容。

检查到形成了一个用户数据包了,则给上层应用发消息。

里面主要用户的就是内存指针的移动,复制,删除的操作。缓冲区其实是个循环队列。

要注意在向缓冲区添加数据的时候要用临界区进行锁定,因为同时发送线程还在读取数据。

接收缓冲区也是同样的。

将发送缓冲区和接收缓冲区和实现成一类使用就更方便了。

PuserInfo=^TuserInfo;

TuserInfo=packed record

A:Array[0..3] of Char;

B:TDateTime;

C:Integer;

D:Array[0..3] of Char;

end;

TUserPack=packed record

PackType:Integer;

DataSize:Integer;

Data:TuserInfo;

end;

function SendUserInfo(Value:TuserInfo):Integer;

var

UserPack:TUserPack;

begin

UserPack.PackType:=1234; //每个类型的包的类型编号是唯一的

UserPack.DataSize:=SizeOf(TuserInfo);

UserPack.Data:=Value;

//添加到发送缓冲区

end;

//收到数据后根据 PackType和 DataSize来确定数据包的大小。