流协议 收发要点

来源:互联网 发布:hash算法 编辑:程序博客网 时间:2024/05/20 20:17


参考:《Windows网络编程技术》7.3.4 节 流协议

大多面向连接的协议同时也是流式传输协议, 对于流套接字上收发数据所用的函数,需要明白的是:它们不能保证对请求的数据量进行读取或写入。比如说,一个2 0 4 8字节的字符缓冲,准备用s e n d函数来发送它。采用的代码是:

char sendbuff[2048];int nBytes = 2048;//Fill sendbuff with 2048 char//Assume s is valid, connected stream socket.ret = send(s, sendbuff, nBytes, 0);

对s e n d函数而言,可能会返回已发出的少于2 0 4 8的字节。r e t变量将设为发送的字节数,这是因为对每个收发数据的套接字来说,系统都为它们分配了相当充足的缓冲区空间。在发送数据时,内部缓冲区会将数据一直保留到应该将它发到线上为止。几种常见的情况都可导致这一情形的发生。比方说,大量数据的传输可以令缓冲区快速填满。同时,对T C P / I P来说,还有一个窗口大小的问题。接收端会对窗口大小进行调节,以指出它可以接收多少数据。如果有大量数据涌入接收端,接收端就会将窗口大小设为0,为待发数据做好准备。对发送端来说,这样会强令它在收到一个新的大于0的窗口大小之前,不得再发数据。在使用s e n d调用时,缓冲区可能只能容纳1 0 2 4个字节,这时,便有必要再提取剩下的1 0 2 4个字节。要保证将所有的字节发出去,可采用下面的代码。

char sendbuff[2048];int nBytes = 2048;int nLeft = nBytes;int ret;int index = 0;//Fill sendbuff with 2048 char//Assume s is valid, connected stream socket.while (nLeft > 0){ret = send(s, &sendbuff[index], nLeft, 0);if (ret == SOCKET_ERROR){//ERRORbreak;}nLeft -= ret;index += ret;}


对在流套接字上接收数据来说,前一段代码有用,但意义不大。因为流套接字是一个不间断的数据流,应用程序在读取它时,和它应该读多少数据之间通常没有关系。如果应用需要依赖于流协议的离散数据,你就有别的事要做。如果所有消息长度都一样,则比较简单,也就是说,5 1 2个字节的消息看起来就像下面这样:对在流套接字上接收数据来说,前一段代码有用,但意义不大。因为流套接字是一个不间断的数据流,应用程序在读取它时,和它应该读多少数据之间通常没有关系。如果应用需要依赖于流协议的离散数据,你就有别的事要做。如果所有消息长度都一样,则比较简单,也就是说,5 1 2个字节的消息看起来就像下面这样:

char recvbuff[2048];int nLeft = 512;int index = 0;int ret;while (nLeft > 0){ret = recv(s, &recvbuff[index], nLeft, 0);if (ret == SOCKET_ERROR){//ERRORbreak;}nLeft -= ret;index += ret;}

消息长度不同,处理也可能不同。因此,有必要利用你自己的协议来通知接收端,即将到来的消息长度是多少。比方说,写入接收端的前4个字节一直是整数,表示即将到来的消息有多少字节。然后,接收端先查看前4个字节的方式,把它们转换成一个整数,然后判断构成消息的字节数是多少,通过这种方式,便开始逐次读取。