阻塞recv()的情况返回少于请求的字节

Adi*_*dil 8 c sockets linux solaris

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

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

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

recv(sockDesc, buffer, size, 0); /* Where size is 100. */
Run Code Online (Sandbox Code Playgroud)

并且只有50个字节由服务器发送然后recv()被阻止,直到100个字节可用或它将返回接收50个字节.

情景可能是:

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

  • 糟糕的协议设计,其中服务器只发送50个字节,而客户端期望100,服务器也在等待客户端的回复(即,套接字关闭连接尚未由recv将返回的服务器启动)

我对Linux/Solaris平台感兴趣.我没有开发环境来自己检查一下.

nos*_*nos 17

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

如果您要发送100字节"消​​息",请记住TCP不提供消息,它只是一个流.如果您正在处理应用程序消息,则需要在应用程序层处理它,因为TCP不会这样做.

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

  • 发送TCP堆栈决定束15个写入呼叫在一起,并且MTU正好是1460,其 - 根据所述到达的数据的定时可能会导致客户端头14级的呼叫来获取100个字节和15呼叫来获取60个字节 - 下次调用recv()时,最后40个字节将会出现.(但是如果你用100的缓冲区调用recv,你可能会得到先前应用程序"message"的最后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;
}
Run Code Online (Sandbox Code Playgroud)

...

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

}
Run Code Online (Sandbox Code Playgroud)


Rob*_*nes 7

行为由两件事决定.recv低水位标记以及你是否通过MSG_WAITALL旗帜.如果传递此标志,则呼叫将阻塞,直到收到请求的字节数,即使服务器崩溃也是如此.另外,只要在SO_RCVLOWAT套接字的接收缓冲区中至少有字节可用,它就会返回.

SO_RCVLOWAT

设置要为套接字输入操作处理的最小字节数.SO_RCVLOWAT的默认值为1.如果SO_RCVLOWAT设置为较大值,则阻塞接收呼叫通常会等待,直到它们收到较低的水位标记值或请求的数量.(如果发生错误,捕获信号,或接收队列中的下一个数据类型与返回的数据类型不同,例如带外数据,它们可能返回低于低水位线.此选项采用int值.请注意,并非所有实现都允许设置此选项.