2010-02-19 34 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

    相關問題