一尘不染

阻止recv()返回小于请求字节的情况

linux

recv()库函数手册页提及的是:

它返回接收的字节数。它通常返回任何可用数据,直到请求的数量,而不是等待收到请求的全部数量。

如果我们使用阻塞recv()调用并要求100字节:

recv(sockDesc, buffer, size, 0); /* Where size is 100. */

服务器仅发送50个字节,然后将recv()其阻止,直到100个字节可用为止,否则它将返回接收50个字节。

情况可能是:

  • sendign仅50个字节后服务器崩溃

  • 错误的协议设计,其中服务器仅发送50个字节,而客户端期望100个字节,并且服务器还等待客户端的答复(即,套接字关闭连接尚未由recv将返回的服务器启动)

我对Linux / Solaris平台感兴趣。我没有开发环境可以自己检查。


阅读 250

收藏
2020-06-07

共1个答案

一尘不染

当内部缓冲区中有数据要返回时,recv将返回。如果您请求100个字节,它不会等到100个字节为止。

如果要发送100字节的“消息”,请记住TCP不提供消息,它只是一个流。如果要处理应用程序消息,则需要在应用程序层进行处理,因为TCP不会这样做。

在许多情况下,调用recv(…,100)时,只有一个recv调用可能无法完全读取另一端的100字节send()调用;这里只是 几个 例子:

  • 发送TCP堆栈决定将15个写调用捆绑在一起,而MTU恰好是1460,这取决于到达数据的时间,可能导致客户端的前14个调用获取100个字节,而15个调用获取60个字节-最后的40个字节将在您下次调用recv()时出现。(但是,如果使用缓冲区100调用recv,则可能会获得前一个应用程序“消息”的后40个字节,以及下一条消息的前60个字节)

  • 发送者缓冲区已满,可能是读取器速度很慢,或者网络拥塞。在某些时候,数据可能会通过,在清空缓冲区时,最后一块数据不是100的倍数。

  • 接收器缓冲区已满,而您的应用程序recv()数据时,它拉出的最后一个块只是部分,因为该消息的整个100字节都不适合缓冲区。

这些场景中的许多场景都很难测试,尤其是在您可能没有很多拥塞或数据包丢失的局域网上-随着您提高/降低消息发送/生成速度的速度,情况可能会有所不同。

无论如何。如果要从套接字读取100字节,请使用类似

int
readn(int f, void *av, int n)
{
    char *a;
    int m, t;

    a = av;
    t = 0;
    while(t < n){
        m = read(f, a+t, n-t);
        if(m <= 0){
            if(t == 0)
                return m;
            break;
        }
        t += m;
    }
    return t;
}

if(readn(mysocket,buffer,BUFFER_SZ) != BUFFER_SZ) {
  //something really bad is going on.

}
2020-06-07