首页  编辑  

Socket接收数据问题

Tags: /超级猛料/Network.网络通讯/Sockt编程/   Date Created:

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.

}