關於SOCKET的阻塞非阻塞recv和send

對於recv和send函數的返回完成,實際上並不是將緩衝區數據成功送入網絡鏈路,而只是成功發送到系統緩衝區或 者是系統緩衝區有數據了!這個系統緩衝區應該是驅動裏分配的緩衝區,NTFS默認大小8k,一般WINDOWS 4K。

在發包時候,因爲TCP提供的是流服務,導致WINSOCK接口會根據緩衝區和數據包的實 際情況自由的對數據包進行組合和分割發送,也就是當客戶端連續多次發送包時(<100ms),多個數據包可能會組合在一起進行了發送,也就是出現 了"粘連"情況,這樣客戶一次收數據時可能會收到其他包的數據,也可能會發生單個數據包被分割的情況,這樣接受到的只是包的一部分,需要重複接受多次才能 得到一個完整的包。但不管怎樣,包的內容是按發送的先後順序到達目的端,並且保證包的完整性,只是接收數據的時候需要進行處理!

對於單線程和多線程發包阻塞情況:

send單線程:如果發送數據大於系統緩衝區長度,或者SOCKET斷開則返回 SOCKET_ERROR,否則函數總是在將指定大小的數據包發送完到系統緩衝區纔會返回。send先檢查協議是否正在發送系統緩衝區的數據,如果是就等 待協議把數據發送完。

1. 系統緩衝區中沒有數據,即每個send間的間隔比較長在每個send後系統一會就發送系統緩衝區中的數據了第二次發送時系統緩衝區就是空的,就保證了每次 能發送一個完整的數據包!

2。協議還沒有開始發送系統緩衝區中的數據即在COPY完客戶緩衝區數據到系統緩衝區後到 系統開始發送系統緩衝區中的數據的時間間隔內如果再發送一次包,如果這時包的長度小於剩餘系統緩衝區的長度則直接再COPY,這時就發生了"粘包"現象, 如果大於了系統緩衝區剩餘大小則等待發送緩衝區數據全部發完再COPY進空的系統緩衝區。

send多線程:在COPY客戶緩衝區數據到系統緩衝區時,每個線程在COPY過程中不會 交叉,因爲當一個線程COPY時會鎖定系統緩衝區,等到全部COPY完另一個線程才能繼續COPY。也就保證了多線程發包時每個包的完整性不會產生數據交 叉。也可能會產生粘包現象。

所以不管怎樣 能保證每一個定義的包的完整性!可以在接受時將定義的包從粘連包裏分出來。

單線程收包和多線程收包:

recv:調用recv函數時,recv先等待系統發送緩衝中的數據被協議傳送完畢,如果 協議在傳送系統發送緩衝中的數據時出現網絡錯誤,那麼recv函數返回SOCKET_ERROR,如果系統的發送緩衝中沒有數 據或者數據被協議成功發送完畢後,recv先檢查套接字系統的接收緩衝區,如果系統接收緩衝區中沒有數據或者協議正在接收數據,那麼recv就一直等待, 只到協議把數據接收完畢。當協議把數據接收完畢,recv函數就把系統的接收緩衝中的數據copy到buf中(注意協議接收到的數據可能 大於buf的長度,所以在這種情況下要調用幾次recv函數才能把系統的接收緩衝中的數據copy完。recv函數僅僅是copy數據, 真正的接收數據是協議來完成的 ),recv函數返回其實際copy的字節數。

多線程時必須同步取數據,否則會數據會被不同線程獲得。

 

也可能產生多次發送包後,系統接受緩衝區有幾個包的數據,可以分批接受也可以一次接受完畢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章