TCP/IP 協議中的滑動窗口

一個例子明白髮送緩衝區、接受緩衝區、滑動窗口協議之間的關係。 
在上面的幾篇文章中簡單介紹了上述幾個概念在TCP網絡編程中的關係,也對應了幾個基本socket系統調用的幾個行爲,這裏再列舉一個例子,因爲對於每個TCP的SOCKET來講,都有一個發送緩衝區和接受緩衝區與之對應,因此這裏只作單方向jiāo流,不作互動,在recv端不send,在send端不recv。細細揣摩其中的含義。 
1、recv端 
在監聽套接字上準備accept,在accept結束之後不作什麼操做,直接sleep好久,也就是在recv端並不作接受數據的操做,在sleep結束以後再recv數據。 
2、send端 
經過查看本系統內核默認的支持的最大發送緩衝區大小,cat/proc/sys/net/ipv4/tcp_wmem,最後一個參數爲發送緩衝區的最大大小。接受緩衝區最大的配置文件在tcp_rmen中。 
將套接字設置爲阻塞,一次發送的buffer大於最大發送緩衝區所能容納的數據量,一次send結束,在發送返回後接着答應發送的數據長度 
測試結果: 
階段一: 
         接受端表現:在剛開始發送數據時,接收端chǔ於慢啓動狀態,滑動窗口大小越來愈大,可是因爲接收端不chǔ理接受緩衝區內的數據,其滑動窗口愈來愈小(由於接受端迴應發送端中的win大小表示接受端還可以接受多少數據,發送端下次發送的數據大小不能超過迴應中win的大小),最後發送端迴應給接受端的ACK中顯示的win大小爲0,表示接收端不可以再接受數據。 
發送端表現:發送端一直不能返回,若是接受端一直迴應win爲0的狀況下,發送端的send就會一直不能返回,這種僵局一直持續到接收端的sleep結束。 
緣由分析:首先須要明白幾個事實,阻塞式I/O會一直等待,直達這個操做完成;發送端接受到接收端的迴應後才能將發送緩衝區中的數據進行清空。 
在接收端不recv,那麼接收端的接受緩衝區內會一直有數據,接受緩衝區滿,致使滑動窗口爲0,致使發送端不能發送數據。可是send操做爲什麼不能反悔呢?send操做只是將應用緩衝區的數據拷貝到發送緩衝區,可是發送緩衝區的數據並無徹底獲得接收端的ACK迴應,因此暫時不能將發送緩衝區中的數據丟棄,致使發送緩衝區的被填滿,這樣應用層中的數據也就不能拷貝到內核發送緩衝區內,也就會一直阻塞在這裏,直到能夠繼續講應用層的數據拷貝到發送緩衝區中,什麼時候觸發這個操做呢?等到發送端迴應win大於0時纔有這樣的操做。 
階段二; 
         接受端:在sleep結束之後,開始調用recv系統調用。這個時候接受端的滑動窗口又開始大於零。那麼這樣就喚醒了發送端繼續發送數據。 
         發送端:發送端接受到接收端win大於0的迴應,這個時候發送端又能夠將應用層buffer中的數據拷貝到內核的發送緩衝區中。 
緣由分析:因爲接受端調用recv將內核接受緩衝區的數據拷貝到應用層中,這樣滑動窗口又大於0了因此激發了發送端繼續發送數據,因爲發送端能夠發送數據了,內核協議棧便將發送緩衝區中的數據發送給接受端,這樣發送緩衝區又有空間了,那麼send操做就能夠將應用層的數據拷貝到發送緩衝區了!這樣的操做一直保持到send操做返回,這樣表明着將應用層的數據所有拷貝到發送緩衝區內,但不表明將數據發送給對端。發送給對端成功的標誌是接受到對端的ACK迴應,這個時候發送端才能夠將發送緩衝區的數據丟棄。不丟棄的緣由是時刻準備重發丟失/出錯的數據! 
Ps: TCP通訊爲了保證可靠xìng,每次發送的數據都須要獲得對方的ACK才確認對方收到了(僅保證對方TCP接收緩衝收到 數據了,但不保證對方應用程序取到數據了),這時若是每次發送一次就要停下來等着對方的ACK消息,顯然是一種極大的資源浪費和低下的效率,這時就有了滑動窗口的出現。
發送方的滑動窗口維持着當前發送的幀序號,已發出去幀的計時器,接收方當前的窗口大小(由接收方ACK通知,大致等於接收緩衝大小-未chǔ理的消息包),接收方滑動窗口保存的有已接收的幀信息、期待的下一幀的幀號等,至於滑動窗口的具體工做原理這裏就不說了。
   一 個socket有兩個滑動窗口(一個sendbuf、一個recvbuf),兩個窗口的大小是經過setsockopt函數設置的,如今問題就出在這裏, 經過抓包顯示,設置的窗口大小沒有生效,最後排查發現setsockopt函數是後來加上的,寫到了listen函數的後面,這樣每次accept出的 socket並無繼承獲得主socket設置的窗口大小,無語啊……
   解決辦法:setsockopt函數提早到listen函數以前,這樣在服務器程序啓動監聽前recvbuf就已經有了,accept後的連接獲得的就是recvbuf了,啓動程序運行,抓包顯示窗口已是指定的大小了。 
1、TCP的滑動窗口大小實際上就是socket的接收緩衝區大小的字節數 
  
2、 對於server端的socket必定要在listen以前設置緩衝區大小,由於,accept時新產生的socket會繼承監聽socket的緩衝區大 小。對於client端的socket必定要在connet以前設置緩衝區大小,由於connet時須要進行三次握手過程,會通知對方本身的窗口大小。在 connet以後再設置緩衝區,已經沒有什麼意義。 
  
3、因爲緩衝區大小在TCP頭部只有16位來表示,因此它的最大值是65536,可是對於一些狀況來講須要使用更大的滑動窗口,這時候就要使用擴展的滑動窗口,如光纖高速通訊網絡,或者是衛星長鏈接網絡,須要窗口儘量的大。這時會使用擴展的32位的滑動窗口大小。 
  編程

相關文章
相關標籤/搜索