TCP传输堆栈的基础是其作者有时记录的许多缓冲区限制。在WinXP SP3上,我认为我遇到了其中一个,并且无法弄清楚原因。
我已经实现了一个简单的客户端来从服务器获取数据(由Java同事编写)。协议是以四个字节写入数据的长度(按网络顺序),然后是数据。服务器以1024字节块将数据写入TCP流。客户端正确接收数据缓冲区的长度,分配内存并在循环中重复调用recv以获取所有数据:
unsigned int TCP_BlockSize = 4096;
unsigned int len;
int result;
...code to request len...
unsigned char *buf = new unsigned char[len];
if( len > TCP_BlockSize)
{
Uint32 currentLen = 0;
result = 0;
Uint32 failCount = 0;
while( currentLen < len && result >= 0)
{
result = recv( sock, buf + currentLen, TCP_BlockSize );
if( result > 0 )
{
currentLen = currentLen + result;
}
else
{
break;
}
}
}
如果我将TCP_BlockSize设置为4095或更低,一切都很好,我可以接收多兆字节的传输。当我尝试4096个大小的接收块时,对剩余数据的最后一个请求是len-currentLen&lt; TCP_BlockSize,总是失败,返回值为-1,并且errno = 0.我尝试了一些实验,比如修改传输数据的大小,介于815054和834246之间的某些地方,4096字节接收块的一切都在蓬勃发展。
另一个细节:服务器在发送最后一个字节后关闭套接字。这引出了一个问题,为什么不返回剩余的数据?从recv返回-1直到流和关闭为止,感觉就像是一个缺陷,因为当流不为空并且关闭接收时它是不明确的 - 1来自recv。
那么如何获取最后的数据?
答案 0 :(得分:2)
尝试类似......
to_rcv = (len - currentlen < TCP_BlockSize) ? len - currentlen : TCP_BlockSize;
result = recv( sock, buf + currentLen, to_rcv);
这样最终的recv只会询问所需的金额,否则它会要求TCP_BlockSize。