1. 程式人生 > >TCP協議-滑動視窗、拆包和粘包

TCP協議-滑動視窗、拆包和粘包

TCP、UDP都可以完成從一端往另一端傳送資料,
只是UDP只是負責從傳送端將資料傳送出去就完了,不再管資料是否傳送到接收端是否已經接收到了;
而TCP不僅負責傳送資料,還確保資料是否送達,TCP是可靠的,而且它也是可以流控的,管理髮送的速度,不能超過裝置的承受能力。

TCP特性


1.可靠性
Reliability,TCP提供資料傳的可靠性,確保接收端是否已接收到資料,如果超時沒有收到接收端的確認,則會重新傳輸,

2.流控的
Data Flow Control,TCP還提供資料傳輸的流控,有一個緩衝區接管,不能傳輸任意大的資料量,這就由滑動視窗來實現這個特性。

滑動視窗Sliding Window

在四層協議中,TCP的下一層就是IP層,IP層協議是不可靠協議,所以需要TCP層自己的確認機制去確認資料是否已經傳輸到接收端了,在較早時候,使用send-wait-send的模式,也叫stop-wait模式,傳送端在傳送資料包package1後,會啟動定時器檢查package1是否收到ACK,定時器到期後,還沒收到ACK則認為接收端沒收到package1,傳送端就會重傳,這樣降低了通訊的效率,這機制叫positive acknowledgment with retransmission (PAR)。

假設每傳送一個包都有一個id,傳送端對每個包進行ACK,那麼傳送端可以一次性發送多個包,而不必等待接收端ACK之後再發下一個,同時接收端也會告訴傳送端它能接收多少,這樣傳送端就不會發送過多的包了,當然也要保證包的順序性,接收端可以先快取提前到的資料,如果超過一定時間,等待的資料還沒到達,則丟掉之前快取的資料。

引入滑動視窗解決這個問題。

先看傳送端的滑動視窗:

1.Sent and Acknowledged
已傳送並且已確認的,資料已經傳輸給接收端並收到ACK,這部分資料已經在視窗之外,因為他們已經傳輸成功了,會從視窗中移除出去,實際的操作是視窗進行合攏,將需要傳輸的資料放進視窗範圍。

2.Send But Not Yet Acknowledged
已傳送但未確認的,資料已傳送到接收端,但還沒收到接收端的ACK,這部分屬於視窗之內,因為這部分資料認為是沒完成傳送的。

3.Not Sent,Recipient Ready to Receive
沒傳送的但接收端有能力接收的,這部分資料已經載入到快取中,也是屬於視窗之內的,其實這部分資料是完全在接收端的告知接受範圍能力之內的,所以傳輸端要儘快傳輸給接收端。

4.Not Sent,Recipient Not Ready to Receive
沒傳送的並且接收端沒能力接收的,超出了接收端的接收範圍了,所以這部分資料是不屬於視窗之內的。


傳送視窗和可用視窗
所以對傳送端來講,屬於可以傳送的視窗之內的,就是2和3點了。2和3的範圍又叫做傳送視窗,傳送視窗的範圍是在TCP進行3次握手時,接收端告知傳送端的,當然接收端在接收過程中也不斷告知傳送端傳送視窗的大小: 3又叫可用視窗: 接收端告知這些資料也是在可接收範圍之內的,但這些視窗範圍還沒傳送資料出去的。


接收端的滑動視窗:

接收端不需要像傳送端那樣等待ACK,所以它沒有確認部分的資料。
1.Received and ACK Not Send to Process
接收到傳送端的資料並且給傳送端發過ACK資訊,但沒被上層應用接收的,所以這部分資料也是在視窗之內的。

2.Received Not ACK
接收到傳送端的資料但沒給傳送端ACK資訊的,這部分屬於Deplay ACK的,所以這部分也是屬於視窗的。

3.Not Received
有空餘的空間,還沒有接收到傳送端的資料。


滑動視窗原理
現在傳送端有報文3、4要傳送,接收端並不是每接收一個就回一個ACK,比如接收端先接收到4,但並不會馬上對4回ACK,而在先放在快取中等待3的空缺補上,如果3也送到了,再回一個ACK(又稱累積ACK),如果3一直不送來,則會把已接收到的4也丟掉,這樣傳送端就執行重傳機制。

1. 假設32~45 這些資料,是上層應用傳送給TCP的,TCP將其分成四個報文段來發往接收端

2. seg1 32~34 seg3 35~36 seg3 37~41 seg4 42~45  這四個片段,依次傳送出去,此時假設接收端之接收到了seg1 seg2 seg4

3. 此時接收端的行為是回覆一個ACK包說明已經接收到了32~36的資料,並將seg4進行快取(保證順序,產生一個儲存seg3 的空缺)

4. 傳送端收到ACK之後,就會將32~36的資料包從傳送並沒有確認切到傳送已經確認,踢出傳送視窗,這個時候視窗向右移動

5. 假設接收端通告的Window Size仍然不變,此時視窗右移,產生一些新的空位,這些是接收端允許傳送的範圍

6. 對於丟失的seg3,如果超過一定時間,TCP就會重新傳送(重傳機制),重傳成功會seg3 seg4一塊被確認,不成功,seg4也將被丟棄

就是不斷重複著上述的過程,隨著視窗不斷滑動,將整個資料流傳送到接收端,實際上接收端的Window Size通告也是會變化的,接收端根據這個值來確定何時及傳送多少資料,從對資料流進行流控。

我們可以通過機器的一些引數,看出TCP的傳送、重傳、連線失效機制。
cat /proc/sys/net/ipv4/tcp_mem
753600    1004800    1507200
cat /proc/sys/net/ipv4/tcp_wmem
4096    16384    4194304
cat /proc/sys/net/ipv4/tcp_rmem
4096    87380    4194304
cat /proc/sys/net/core/wmem_default
124928
cat /proc/sys/net/core/wmem_max
124928
cat /proc/sys/net/core/rmem_default
124928
cat /proc/sys/net/core/rmem_max
124928
cat /proc/sys/net/ipv4/tcp_retries2
15
cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
參照
http://www.360doc.com/content/14/0606/16/3300331_384326124.shtml


拆包和粘包

UCP是基於報文傳送的,UDP報文的首部會有16bit來表現UDP資料的長度,所以不同的報文之間是可以區別隔離出來的,所以應用層接收傳輸層的報文時,不會存在拆包和粘包的問題;
而TCP是基於位元組流傳的,應用層和傳輸層之前資料互動是大小不等的資料塊,但TCP對這些資料塊只是一連串的資料流,它並不知道哪些資料塊跟哪些資料塊是該一起發,哪個資料塊是應該單獨一塊的,因為TCP並沒有像UDP那樣首部有資料長度,所以TCP存在拆包和粘包的問題。

有了上面滑動視窗的知識,相信比較好理解為什麼TCP會對資料塊進行拆包和粘包的處理了,當然還有套接字(socket)快取區可用大小的原因等等。

原因

1.要傳送的資料包大於傳送快取區的可用空間時,資料被會拆包;
2.要傳送的資料大於MSS(Maximum Segment Size最大報文段),TCP在傳送前會對資料進行拆包;
TCP在三次握手建立連線過程中,會在SYN報文中使用MSS選項功能,協商互動雙方能夠接收的最大段長MSS值。
MSS是傳輸層TCP協議範疇內的概念,它是標識TCP能夠承載的最大的應用資料段長度,因此,MSS=MTU-20位元組TCP報頭-20位元組IP報頭,那麼在乙太網環境下,MSS值一般就是1500-20-20=1460位元組。
3.傳送的資料小於快取區,則TCP會將幾次的資料一次性發送,會存在粘包;

拆包、粘包舉例

比如傳送端要往接收端傳送2個數據包
1.收到2個數據包,沒傳送拆包和粘包情況;
2.收到1個數據包,TCP把2個數據包合成1個傳送給接收端了,這樣應用層不能處理合成1個的兩個資料包,應用層不知道兩個資料包之間的分隔在哪,所以很難處理,這是粘包問題;
3.收到2個數據包,但1個數據包產生了粘包(傳送端的1個半資料包),另1個數據包產生了拆包(只有傳送端中1個數據包的半個包),這樣應用層也是很難處理粘包、拆包的;

解決

由於TCP是不知道應用層的資料包的分界的,所以我們應用層是決定不了傳輸層對資料包拆包還是粘包,不過應用層可以通應用層協議棧設計給資料包加分界標記,來處理最後接收到的資料,不管拆分還是粘包都可以處理好。

1.傳送端給資料包增加首部,首部包含資料包中資料的長度,這樣接收端的應用層接收資料後,根據首部中的長度就知道資料的實際長度了,可以很好處理資料了。
通常設計思路,比如第1個欄位使用32int表示資料的長度,接著是資料內容。
2.設定資料包的長度為固定的長度,不夠資料則以空格填補;
3.應用層在傳送每個資料包時,給每個資料包加分界標記,比如回車換行,

在接收端接收的資料包個數總比傳送端傳送的個數少時,那是傳送端的傳送速度過快,導致接收端接收不過來,接收端會告知傳送端的傳送視窗為0,傳送端新來資料只能暫存在傳送快取區中,當傳送快取區溢位後,則會出現丟包,可以增大發送快取區來緩解,就是擁堵問題。