2010-02-19 38 views
6

recv()库函数手册页提到:情况下,阻塞的recv()返回时小于请求的字节

它返回接收的字节数。它通常会返回任何可用的数据,达到所需数量,而不是等待收到所需的全部数额。

如果我们使用的是阻塞recv()呼吁,并要求100个字节:

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

只有50字节由服务器然后这recv()被阻塞,直到100个字节发送可用,否则将返回接收50个字节。

的情况可能是:只有50 sendign字节

  • 糟糕的协议设计,其中服务器仅发送50个字节后

    • 服务器崩溃而客户期待100和服务器也在等待客户端的回复(即套接字关闭连接尚未由recv将返回的服务器启动)

    我对李nux/Solaris平台。我没有开发环境来自己查看。

  • 回答

    13

    的recv会返回。如果您请求100个字节,它不会等到有100个字节。

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

    有其中的100个字节的发送()调用可能还没有完全在另一端调用时只有一个recv调用的recv(...,100)读很多很多的条件;这里只是一个几个例子:

    • 发送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. 
    
    } 
    
    +0

    感谢您的详细解释。只需确认是否对* blocking * recv()调用也是如此? (即recv()返回的请求字节数小于) – Adil 2010-02-19 13:03:31

    +0

    是的,这对阻塞recv呼叫是正确的。 – nos 2010-02-19 18:25:32

    2

    如果你正确地读取的报价,最常见的情况是:

    • 套接字接收数据。这100个字节需要一些时间。
    • 进行recv()调用。
      • 如果在缓冲区大于0字节的recv()返回什么是可用的,并且不等待。
      • 虽然有0字节的可用它块和纸系统的粒度确定有多长。当有在内部缓冲区的数据返回
    +0

    太感谢这意味着,如果阻塞的recv()发出和数据是可用的(小于要求的),它将返回的任何数据是abailable。对? – Adil 2010-02-19 13:07:52

    7

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

    SO_RCVLOWAT

    设置的最小字节数 过程插座输入操作。 SO_RCVLOWAT的默认值为 1.如果SO_RCVLOWAT设置为较大值,通常阻止接收呼叫 等待,直到它们收到 较小的低水位值或 请求的数量。 (它们可以比低水位标志返回 更少如果发生错误 ,一个信号被捕获,或 数据的类型下在接收 队列是不同比返回, 例如带外的数据)。此选项 采用int值。请注意,并非所有的 实现都允许将此选项设置为 。

    +0

    SO_RCVLOWAT是套接字选项。如果我们没有设置任何套接字选项并且没有将标志传递给recv(),并且发出阻塞recv()调用,它是否会等待所有请求的字节? (套接字关闭操作也未被初始化) – Adil 2010-02-19 13:06:18

    +1

    在你描述的情况下,它将返回50个字节。它将**不**等待完整的100个字节,除非你将'MSG_WAITALL'标志传递给'recv'。 – 2010-02-19 13:33:15

    相关问题