Socket接收数据问题
其实现在Socket编程序已经非常方便了,这些细节问题已经被组件包容起来,我们根本不需要处理!
我在 Delphi3.0 编的程序里用 WinSock 实现数据库中数据的发送和接收 . 程序在 95 之间运行正常,可如果一台 95 ,一台 NT 之间收发的时候发现用 NT 发送, 95 接收没问题,反过来却总是报错 . 跟踪调试后发现在接收相同的数据时 ;
95 下 Recv(socket,buffer,size,0) 返回值正常 , 等于 size
NT 下 Recv(socket,buffer,size,0) 却总是小于 size
这是什麽原因 ?
------------------------------------------------------------------------------
来自:pegasus 时间:99-1-13 下午 01:38:36
这个并没有任何错误发生,只是因为您还没有正确理解 TCP/IP 网络传输层传送数据的原理 ,TCP/IP 的传输层提供的可靠的传输协议 TCP, 是面向字节流的,并不是面向消息报文的,发送接收的过程中会有协商, 按照一定的缓冲区分块发送。所以,您并不能指望只要您提供了 buffer, 会对方整个接收到。
例如:
send(socket, buffer, 8192, 0);
系统可能分成若干个 1 , 2K 的数据包依次发送,这样一来,接收的程序
recv(socket, buffer, 8192, 0);
就不能够一次把 8192 个字节全部接收到,因为这里接收方并不知道发送方的 8192 的边界,只知道字节流。
您需要多次调用 recv 来接收需要的长度,其实,发送方也是一样,并不能保证一次就把您所要求的数据全部发送完毕,因为发送方的缓冲区也是有限的,也需要您根据 send 的返回值,多次调用来保证全部发送完成。
而这里的 buffer 的 size 只属于更高层的约定(既是所谓的应用层协议啦!) . 如果发送方面只 perfect_send(socket, buffer, 123, 0); 但是接受方期待的却是能够 perfect_recv(socket, buffer, 4096, 0); 那么就可能发生"死锁 " !
提供解决办法使用两个函数把 send 和 receive 包装起来,如下: (C(++) version)
int SafeSend(int sockfd, const void* lpBuf, unsigned int nBufLen, int nFlags)
{
int iSendOffSet=0;
int iSendLen;
while (iSendOffSet<nBufLen)
{
if ( (iSendLen=send(sockfd, (const char*)lpBuf+iSendOffSet, nBufLen-iSendOffSet, nFlags))>0)
iSendOffSet+=iSendLen;
else
return iSendLen; // It's an error code
}
assert(iSendOffSet == nBufLen);
return iSendOffSet; // Must be nBufLen now.
}
int ReceiveBuf(int sockfd, void* Buf, unsigned int nBufLen, int nFlags)
{
int iReceiveOffSet=0;
int iReceiveLen;
while (iReceiveOffSet<nBufLen)
{
if ( (iReceiveLen=recv(sockfd, (char *)Buf+iReceiveOffSet, nBufLen-iReceiveOffSet, nFlags))>0)
iReceiveOffSet+=iReceiveLen;
else
return iReceiveLen; // It's an error code
}
assert(iReceiveLen == nBufLen);
return iReceiveOffSet; // Must be nBufLen now.
}