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