如何解决客户端接收到一次多包数据? (100分)

  • 主题发起人 主题发起人 sgming815
  • 开始时间 开始时间
S

sgming815

Unregistered / Unconfirmed
GUEST, unregistred user!
如何解决数据粘包(发送方分多次发送的数据在接收方一次性收到)问题;有人能答,不胜感激.
我们知道,引起这个问题有可是发送端,也可能是接收端,发送端引起本可以通过用PUSH完全解决,但在Delphi中如何处理?接收端由于系统接收过慢而引起的粘包现象又如何解决?(使用TServerSocket与TClientSocket控件 )

 
不知道你用什么控件通讯
 
使用TServerSocket与TClientSocket控件
 
最简单的办法,但效率也最低:发送方延时sleep(0)
 
因该来说使用tcp协议,不需要你考虑数据的传送速率问题。
不知道你是怎么发现“接收端由于系统接收过慢而引起的粘包现象”的?
 
sleep显然是不行的,不管从原理上还是实际试验都一样,不过对ego的回答还是非常感谢,另外,cnwinds你是没明白我的意思吗
 
定义你消息体的大小,在接受段分析,小于一个消息体大小的就当作碎片保留,直到有完整的包再处理分析!每次都是这样,即使一次获取多个包,也每次取一个出来分析!

通讯协议应该定义好!
 
恩,oldsheep35的做法室最好的,最后说一点,写好的程序最好用猫测试,这样才能保证稳定星
 
关键是这样有没有出现错误呀????
我们知道报文发送后到接收方是要组合起来的呀,
难道这样会粘包????反正系统会处理的啦,
报文都是编了号的呢(看书上说的)!!!

对此我是白痴,不过就会顶,呵呵~~~~
 
sleep被否定了,呵呵,那就来个分包读取吧 ^_^

所有关系到收发数据的缓冲区都属于简单的char类型,即面向字节的数据。

{接收端}
const
BackLog = 5;
var
wsaData: TWSAData;
ServerAddr: TSockAddrIn;
ClientAddr: PSockAddr;
AddrLen: PInteger;
buf: TBuf;
nLeft, idx, ret: integer;
begin
FreeOnTerminate := true;

WSAStartup(MakeWord(2,2), wsaData);

ListenSock := socket(AF_INET, Sock_Stream, IPProto_TCP);

ServerAddr.sin_family := AF_INET;
ServerAddr.sin_port := htons(port);
ServerAddr.sin_addr.S_addr := htonl(INADDR_ANY);
bind(ListenSock, ServerAddr, SizeOf(ServerAddr));

listen(ListenSock, BackLog);

new(ClientAddr);
new(AddrLen);
ClientSock := accept(ListenSock, ClientAddr, AddrLen);
if ClientSock = socket_error then
raise exception.Create(IntToStr(wsaGetLastError));

while not self.Terminated do
begin

nLeft := BufSize;
idx := 0;
while nLeft > 0 do //如果nLeft=0,说明已完整地读取了一个数据包
begin
ret := recv(ClientSock, buf[idx], nLeft, 0);
if ret = socket_error then continue;
dec(nLeft, ret); //nLeft := 数据包长度 - 已读取的长度 = 未读取长度
inc(idx, ret); //已读取的长度,作为buf的开始
end;

FMsg := buf;
FMsg := FMsg + #13;
Synchronize(ShowMsg);
end;

dispose(AddrLen);
dispose(ClientAddr);
CloseSocket(ClientSock);
CloseSocket(ListenSock);
WSACleanup;
end;

*************************************************************************************

{发送端}
const
IP = '192.168.1.6';
var
wsaData: TWSAData;
ServerAddr: TSockAddrIn;
buf: TBuf;
nLeft, idx, i, ret: integer;
str: string;
begin
FreeOnTerminate := true;

WSAStartup(MakeWord(2,2), wsaData);

s := socket(AF_INET, sock_stream, IPProto_TCP);

ServerAddr.sin_family := af_inet;
ServerAddr.sin_port := htons(port);
ServerAddr.sin_addr.S_addr := inet_addr(IP);
if connect(s, ServerAddr, SizeOf(ServerAddr)) = socket_error then
raise exception.Create(IntToStr(wsaGetLastError));

while not Self.Terminated do
begin
for i:=0 to 20 do
begin
str := IntToStr(i);
buf := StrToBuf(str);

nLeft := BufSize;
idx := 0;

while nLeft > 0 do
begin
ret := send(s, buf[idx], nLeft, 0);
if ret = socket_error then
begin
FMsg := '发送错误:' + buf;
Synchronize(ShowMsg);
end;
dec(nLeft, ret);
inc(idx, ret);
end;

end;
FMsg := '发送完毕.';
Synchronize(ShowMsg);

ret := recv(s, buf, BufSize, 0);
if ret = socket_error then
continue;
FMsg := '[收到字节数]' + IntToStr(ret);
Synchronize(ShowMsg);
FMsg := '[收到的内容]' + buf;
Synchronize(ShowMsg);
FMsg := '--------------------------';
Synchronize(ShowMsg);
end;

CloseSocket(s);
end;
 
后退
顶部