tcp 发送数据长度比预设缓存大_一文秒懂 TCP/IP实际五层结构(下篇)
點擊上方藍字關注我們!
引言
本運維老狗在TCP/IP實際五層結構的上篇和中篇中詳細講解了TCP/IP實際結構,以及以太網協議、IP協議、和UDP協議。有同學留言催更,迫切的想看本老狗對TCP協議的講解。應同學們的要求,TCP/IP實際五層結構(下篇)又在運維間隙中趕制出來了。廢話不多少,直接上干貨。TCP協議介紹
我們在中篇中介紹了傳輸層的UDP協議,這里我們來看看傳輸層的另外一個協議,TCP協議。雖然它倆同屬傳輸層,但它倆的性格完全不同。如果把UDP協議形容為愣頭青,則把TCP協議形容為諸葛亮一點不為過。TCP協議“做事”三思而后行、運籌帷幄。TCP協議有豐富的特性,支撐著它的“諸葛亮”形象,比如它有連接管理機制、滑動窗口、窗口控制、重發機制、流控制、擁塞控制、慢啟動、快速重傳等等功能,不可謂不豐富。這些名詞看起來深奧難懂,但同學們不用擔心,雖然TCP協議是TCP/IP協議簇中最復雜的協議,但本老狗會努力嘗試用簡單的語言講透TCP協議。TCP提供一種面向連接的、可靠的字節流服務。面向連接意味著兩個使用TCP的應用在彼此交換數據之前必須先建立一個TCP連接,也就是說要先建立通道,后面數據才能在通道中傳輸。小做復習,回顧一下TCP首部的位置。TCP數據報作為IP數據報的數據部分,包含在IP首部中。如下圖所示:TCP首部
TCP首部比較復雜,TCP首部正常為20個字節(不包含選項部分),如果選項部分有內容,最大可達60個字節。下面來分析IP首部的具體組成。
(1)源端口號(16位)、目的端口號(16位)
端口號用于標識應用層的協議。
其中1-1023為知名端口號和預留端口號。
1024-65535為臨時端口號,分配給應用臨時使用
(2)序列號(32位):序列號,有的資料中也叫做“序號”
(3)確認序列號(32位):Ack,有的資料中也叫做“確認應答號”
老狗這把序列號和確認序列號串起來講,先使用醉漢和他老婆做個比喻。
序列號就像一個醉漢,確認序列號就像他的老婆。醉漢說話老是重復,他老婆聽后一直在提醒他:“嗯,這句話你說過了”,醉漢說著說著打起了呼嚕,他老婆推醒他:“死鬼,醒醒,你剛才說的咱家有大額存款,在哪兒呢,快說說”。
這里可以看出,發送端有時候會發送重復序列號的數據包,確認序列號可以幫其找出重復數據包。同時,發送端有時候還會出現超時為應答等情況,確認序列號通過重傳機制告知發送端。
序列號和確認序列號的作用大致說清楚了,下面看個圖,再做些說明。
序列號由隨機生成的32bit數值作為初始值。序列號的數值是指發送數據的相對位置。每發送一次數據,就累計加一次該數據字節大小。另外,在建立連接和斷開連接時發送的SYN包和FIN包雖然并不攜帶數據,但是也會作為一個字節增加對應的序列號。
確認序列號的數值為發送確認的一端所期望收到的下一個序號。因此,確認序列號應當是上次已成功收到數據字節序號加 1。
剛才說到“序列號由隨機生成的32bit數值作為初始值”,有同學會頓生疑問,他看到的TCP會話的seq都是從0開始的,這又是怎么回事?
這里做個解釋,wireshark為了讓咱們分析數據包時的方便,使用了相對序列號。可以在wireshark的首選項中找到這個選項,不喜歡使用相對序列號的同學可以去掉勾選,如下圖:
(4)首部長度(4位):
該字段長4位,單位為4字節,即TCP首部的最大長度可為15*4=60個字節。正常的首部長度為20個字節,因此選項部分的最大長度可為40個字節。
通過下圖展示的數據包,可以看到首部字段值的二進制是“0101”,換成十進制就是5。計算出來首部長度是:4字節*5 = 20字節。
看圖仔細的同學會發現上圖中有[TCP segment Len:1396]的字眼。但同時會發現,TCP首部中并沒有關于TCP段(即數據部分)長度的字段。
下圖為點擊到這個字眼上的情況,發現下面的十六進制的著色位置和上圖一樣。
老狗這里做個解答。這個字眼的內容是用“[]”框起來的,意思就是不是通過直接讀數據讀出來的,而是wireshark計算出來的。
計算過程如下:Frame長度1450字節,Ethernet首部14字節,IP首部20字節,TCP首部20字節。這么一算,正好TCP數據部分是1396字節。
(5)保留(6位):暫無作用
(6)控制位(6位):在TCP首部中有6個控制位。它們中的多個可同時被設置為1。
URG:緊急指針。
ACK:確認序號有效(確認應答):TCP規定除最初建立連接時的SYN包外,其他數據包ACK必須置位。
PSH:接收端應該盡快將這個報文段交給應用層。PSH為0時,則不需立即傳送而先進行緩存。
RST:重置連接,RST為1時表示TCP連接出現異常,必須強制斷開連接。
SYN:同步序號用來發起一個連接
FIN:發端完成發送任務:置位后表示此端不再有數據發送,希望斷開連接(單向傳輸斷開)。
(7)窗口(16位):
TCP的流量控制是由連接的每一端通過聲明各自端的窗口大小來控制的。窗口字段占用16 bit,即窗口的范圍為0-65535字節。這里先提一嘴,通過選項部分的窗口擴大因子(windows scale)可將窗口擴大為32bit字段。
說完窗口大小,接下來看看滑動窗口。
滑動窗口的引入,是為了解決“停止等待”的缺點的。“停止等待”顧名思義,就是一端發送一次數據后,就必須停止發送數據,等待對端回復確認后,再進行發送。這種方式導致網絡傳輸效率低下。反觀滑動窗口機制,在窗口內的數據即使沒有收到確認應答也可以繼續發送數據。窗口的小大就是指無需等待確認應答而可以繼續發送數據的最大值。
滑動窗口的機制如下圖所示。
從圖中看到,滑動窗口的大小為6字節(僅做展示),此時已經滑動至第4-9字節的位置,說明第1-3字節已經發送完成并被確認。第4-6字節剛被發送,還未確認,此時可用的窗口大小還剩3字節(第7-9字節)可以繼續發送并不用被立刻確認。同時,第10字節之后的數據還未包含在窗口內部,暫時不能發送。
老狗這里說個知識點,滑動窗口的大小不是隨時更新,也不是發送ack確認后就會增大。需要等到接收端的緩存數據已經被應用層讀走,并且接收端主動更新自己的窗口后。發送端才能發送更新后窗口大小的數據。
(8)檢驗和(16位):
檢驗和覆蓋了整個的TCP報文段:TCP首部和TCP數據。檢驗和一個強制性的字段。
(9)緊急指針(16位):
緊急指針只有在URG為1時才有效,用于處理緊急數據。一般在暫時中斷通信的情況下使用。比如在web瀏覽器上點擊停止按鈕,或者在telnet時輸入crtl+c時,都會有URG置位的數據包。
(10)選項(0-60字節):
常用的選項包括MSS、窗口擴大因子、SACK等,下圖展示TCP握手的SYN階段數據包的選項內容:
這里重點介紹一下MSS、窗口擴大因子、選擇性確認(SACK)
MSS 最大分段長度:TCP數據包每次傳輸的最大數據分段大小,數據分段大小指的是IP數據包的數據(TU值減去IPv4 頭部和TCP的頭部得到的值)。
TCP協議在建立連接的時候通常要協商雙方的MSS值,通訊雙方會根據雙方提供的MSS值的最小值確定為這次連接的最大MSS。
MSS的協商過程如下圖所示:
窗口擴大因子:WS是一個用來改善TCP吞吐量的選項。可將原有窗口大小擴充至32bit。
窗口擴大因子只有主動連接方的第一SYN可以發送攜帶。
窗口擴大因子只有在發起方的第一個SYN中包含,接收端收到帶有窗口擴大因子的選項后,可以發送自己的窗口擴大因子(如果支持)。只有在雙方都支持的情況下,后續數據才能使用擴大后的窗口。
咱們現在抓包看看窗口擴大因子,如下圖。第1幀中看到ws=256,即原有窗口大小擴容256倍。通過展開分析,看到窗口擴大因子使用了8位(即窗口大小擴容2的8次方倍)。第2幀的分析與第1幀相同,窗口擴容128倍。
SACK(確認選擇):SACK使TCP擁有了選擇確認的能力。
當發送端收到接收端返回的SACK后,就知道哪些報文是接收端已經收到的,進而將接收端沒有收到的報文進行重傳。注意:SACK協議需要通信雙方都支持。
SACK允許選項(類型值為4),該選項只允許在有SYN標志的TCP包中(會話建立時的前兩個包),分別表示是否支持SACK功能。
SACK選項(類型值為5),選項長度可變,用來選擇性的確認數據的序列號范圍。
TCP會話的建立與終止
TCP會話的建立過程如下圖所示。為了方便查看,我們這里用相對序列號來進行展示。
(1)第一次握手
客戶端執行主動打開(active open)連接,發送一個SYN段指明客戶端打算連接的服務端的端口,以及初始序號(ISN)。
發送內容包括:SYN=1,Seq=J
(2)第二次握手
服務器端收到SYN,執行被動打開(passive open)連接,服務器發回包含服務器的初始序號的SYN報文段,作為應答。同時,將確認序號(Ack)設置為客戶的ISN加1以對客戶的SYN報文段進行確認。一個SYN將占用一個序號。
發送內容包括:SYN=1,ACK=1,Seq=K,Ack=J+1
(3)第三次握手
客戶端收到服務器ACK回包后,首先進入ESTABLISHED狀態,之后發送ACK給服務器,最后服務器也進入ESTABLISHED狀態。
發送內容包括:ACK=1,Seq=J+1,Ack=K+1
TCP會話的結束過程如下圖所示,為了方便查看,我們這里仍用相對序列號來進行展示。
(1)第一次揮手
客戶端主動關閉,進入FIN_WAIT_1狀態,收到FIN包的服務器端進入被動關閉CLOSE_WAIT狀態。
發送內容包括:FIN=1,ACK=1,Seq=M,Ack=Z
2.第二次揮手
服務器端收到FIN包之后,會向客戶端回送ACK,客戶端收到后,進入FIN_WAIT_2狀態 ?(FIN也占用一個序列號)。
發送內容包括:ACK=1,Seq=Z,Ack=M+1
3.第三次揮手
服務器端進入LAST_ACK狀態,發送FIN包至客戶端,客戶端收到后進入TIME_WAIT狀態(即2MSL狀態)。發送內容:FIN=1,ACK=1,Seq=N,Ack=M+1
4.第四次揮手
客戶端收到FIN包之后,會向服務器端回送ACK,服務器端收到后,進入CLOSEE狀態。發送內容: ACK=1,Seq=M+1, Ack=N+1
注意:ACK不占序列號,SYN和FIN各占用1字節序列號。
TCP狀態遷移
TCP狀態遷移是個復雜的過程,下圖(圖片來自網絡)展示了TCP狀態遷移的全貌,圖中用粗的實線箭頭表示正常的客戶端狀態變遷,用粗的虛線箭頭表示正常的服務器狀態變遷。
TCP狀態遷移中的一些狀態。
(1)FIN_WAIT_2狀態
在FIN_WAIT_2狀態客戶端已經發出了FIN,并且服務端也已對它進行確認。除非客戶端在實行半關閉,否則將等待另一端的應用層意識到它已收到一個文件結束符說明,并向客戶端發一個FIN來關閉另一方向的連接。只有當另一端的進程完成這個關閉,客戶端才會從FIN_WAIT_2狀態進入TIME_WAIT狀態。
這意味著客戶端可能永遠保持這個狀態。另一端也將處于CLOSE_WAIT狀態,并一直保持這個狀態直到應用層決定進行關閉。所以需要定時器來結束這個狀態。
一般防火墻都有解決FIN_WAIT_2狀態的超時時間設置。如果超時,防火墻會向雙向發送RESET來踢掉連接。
(2)2MSL等待時間
TIMEWAIT狀態也稱為2MSL等待狀態。每個具體TCP實現必須選擇一個報文段最大生存時間MSL。它是任何報文段被丟棄前在網絡內的最長時間。不同的操作系統有不同的規定,常用值是30秒,1分鐘或2分鐘。在2MSL等待期間socket使用的本地端口默認情況下不能再被使用。這個端口只能在2 MSL結束后才能再被使用。
以上之所以說默認情況下才有2MSL,是因為Linux系統有個端口快速回收機制。通過將cat /proc/sys/net/ipv4/tcp_tw_recycle設置為1,將cat /proc/sys/net/ipv4/tcp_timestamps設置為1,來實現TIME_WAIT狀態快速回收,即無需等待兩倍的MSL這么久的時間,而是等待一個重傳時間即釋放端口。
(3)TCP重傳
TCP的重傳分為兩種:超時重傳、確認重傳(又叫快速重傳)
首先來看第一種重傳,超時重傳。以客戶端發送數據包至服務器端,但服務器端超時仍不進行回復確認(這里指的不回復,可以是客戶端發送數據時丟包,或者服務器端回復時丟包),則啟動超時重傳機制。重傳的數據分析過程下圖所示。同時超時重傳遵循的退避機制。
接下來看第二種重傳,確認重傳(也叫快速重傳),用于未啟用SACK的情況下。舉例說明,如下圖所示。:如果客戶端發出了1,2,3,4,5份數據,第一份先到送了,于是服務器端就發送Ack=2,結果2號包因為某些原因沒收到,3號包到達了,還是Ack=2,后面的4號和5號包都到了,但是還是Ack=2,因為2還是沒有收到,于是發送端收到了三個Ack=2的確認(這里就是確認重傳),知道了2號包還沒有到,于是就馬上重傳2號包。于是,服務器端收到了2號包,此時因為3,4,5號包都收到了,于是Ack=6,則客戶端發送的6份數據都進行了確認。
總結
本篇著重介紹了TCP協議,包括TCP協議TCP首部構成、TCP會話的建立和終止過程、及TCP狀態遷移中常用的一些狀態。
通過本篇的介紹,并結合上一篇UDP的介紹,同學們應該能夠看到UDP和TCP的區別了。就因為它們直接有明顯的區別,才造成了它們兩者的應用場景完全不同。
UDP協議無狀態,傳輸效率高,可用于視頻類、音頻類、廣播類的服務中。
TCP協議有狀態,而且傳輸可靠,可用于文件傳輸、網頁瀏覽、郵件收發等服務中。
至此TCPIP協議實際結構的五層結構的基本框架就勾勒出來了,有興趣的同學到枯燥加班狗中可以把三篇文章結合起來學習,效果更佳哦。
相關閱讀:
一文秒懂 TCPIP實際五層結構(上篇)
一文秒懂 TCP/IP實際五層結構(中篇)
Wireshark數據包分析三板斧
如果喜歡請點擊下方在看
總結
以上是生活随笔為你收集整理的tcp 发送数据长度比预设缓存大_一文秒懂 TCP/IP实际五层结构(下篇)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python双向索引什么意思_(转)Py
- 下一篇: vue 父组建获取子组建方法为获得_Vu