來自公眾號:架構文摘
TCP協(xié)議全稱為:Transmission Control Protocol
行嗤,是一種面向鏈接已日、保證數(shù)據(jù)傳輸安全、可靠的數(shù)據(jù)傳輸協(xié)議栅屏。為了確保數(shù)據(jù)的可靠傳輸捂敌,不僅需要對發(fā)出的每個字節(jié)進行編號確認,還需要驗證每一個數(shù)據(jù)包的有效性既琴。每個TCP數(shù)據(jù)包是封閉在IP包中的占婉,每個一IP包的后面緊跟著的是TCP頭懂拾,TCP報文格式如下:
源端口和目的端口字段
TCP源端口(Source Port):源計算機上的應用程序的端口號辣卒,占 16 位脖镀。
TCP目的端口(Destination Port):目標計算機的應用程序端口號椭懊,占 16 位翎嫡。
序列號字段
CP序列號(Sequence Number):占 32 位囤萤。它表示本報文段所發(fā)送數(shù)據(jù)的第一個字節(jié)的編號驮俗。在 TCP 連接中西乖,所傳送的字節(jié)流的每一個字節(jié)都會按順序編號松靡。當SYN標記不為1時简僧,這是當前數(shù)據(jù)分段第一個字母的序列號;如果SYN的值是1時雕欺,這個字段的值就是初始序列值(ISN)岛马,用于對序列號進行同步棉姐。這時,第一個字節(jié)的序列號比這個字段的值大1啦逆,也就是ISN加1伞矩。
確認號字段
TCP 確認號(Acknowledgment Number,ACK Number):占 32 位夏志。它表示接收方期望收到發(fā)送方下一個報文段的第一個字節(jié)數(shù)據(jù)的編號乃坤。其值是接收計算機即將接收到的下一個序列號,也就是下一個接收到的字節(jié)的序列號加1沟蔑。
數(shù)據(jù)偏移字段
TCP 首部長度(Header Length):數(shù)據(jù)偏移是指數(shù)據(jù)段中的“數(shù)據(jù)”部分起始處距離 TCP 數(shù)據(jù)段起始處的字節(jié)偏移量湿诊,占 4 位。其實這里的“數(shù)據(jù)偏移”也是在確定 TCP 數(shù)據(jù)段頭部分的長度瘦材,告訴接收端的應用程序厅须,數(shù)據(jù)從何處開始。
保留字段
保留(Reserved):占 4 位宇色。為 TCP 將來的發(fā)展預留空間九杂,目前必須全部為 0。
標志位字段
CWR(Congestion Window Reduce):擁塞窗口減少標志宣蠕,用來表明它接收到了設置 ECE 標志的 TCP 包例隆。并且,發(fā)送方收到消息之后抢蚀,通過減小發(fā)送窗口的大小來降低發(fā)送速率镀层。
ECE(ECN Echo):用來在 TCP 三次握手時表明一個 TCP 端是具備 ECN 功能的。在數(shù)據(jù)傳輸過程中皿曲,它也用來表明接收到的 TCP 包的 IP 頭部的 ECN 被設置為 11唱逢,即網(wǎng)絡線路擁堵。
URG(Urgent):表示本報文段中發(fā)送的數(shù)據(jù)是否包含緊急數(shù)據(jù)屋休。URG=1 時表示有緊急數(shù)據(jù)坞古。當 URG=1 時,后面的緊急指針字段才有效劫樟。
ACK:表示前面的確認號字段是否有效痪枫。ACK=1 時表示有效。只有當 ACK=1 時叠艳,前面的確認號字段才有效奶陈。TCP 規(guī)定,連接建立后附较,ACK 必須為 1吃粒。
PSH(Push):告訴對方收到該報文段后是否立即把數(shù)據(jù)推送給上層。如果值為 1拒课,表示應當立即把數(shù)據(jù)提交給上層徐勃,而不是緩存起來事示。
RST:表示是否重置連接。如果 RST=1疏旨,說明 TCP 連接出現(xiàn)了嚴重錯誤(如主機崩潰)很魂,必須釋放連接扎酷,然后再重新建立連接檐涝。
SYN:在建立連接時使用,用來同步序號法挨。當 SYN=1谁榜,ACK=0 時,表示這是一個請求建立連接的報文段凡纳;當 SYN=1窃植,ACK=1 時,表示對方同意建立連接荐糜。SYN=1 時巷怜,說明這是一個請求建立連接或同意建立連接的報文。只有在前兩次握手中 SYN 才為 1暴氏。
FIN:標記數(shù)據(jù)是否發(fā)送完畢延塑。如果 FIN=1,表示數(shù)據(jù)已經(jīng)發(fā)送完成答渔,可以釋放連接关带。
窗口大小字段
窗口大小(Window Size):占 16 位沼撕。它表示從 Ack Number 開始還可以接收多少字節(jié)的數(shù)據(jù)量宋雏,也表示當前接收端的接收窗口還有多少剩余空間。該字段可以用于 TCP 的流量控制务豺。
TCP 校驗和字段
校驗位(TCP Checksum):占 16 位磨总。它用于確認傳輸?shù)臄?shù)據(jù)是否有損壞。發(fā)送端基于數(shù)據(jù)內(nèi)容校驗生成一個數(shù)值笼沥,接收端根據(jù)接收的數(shù)據(jù)校驗生成一個值蚪燕。兩個值必須相同,才能證明數(shù)據(jù)是有效的敬拓。如果兩個值不同邻薯,則丟掉這個數(shù)據(jù)包。Checksum 是根據(jù)偽頭 + TCP 頭 + TCP 數(shù)據(jù)三部分進行計算的乘凸。
緊急指針字段
緊急指針(Urgent Pointer):僅當前面的 URG 控制位為 1 時才有意義厕诡。它指出本數(shù)據(jù)段中為緊急數(shù)據(jù)的字節(jié)數(shù),占 16 位营勤。當所有緊急數(shù)據(jù)處理完后灵嫌,TCP 就會告訴應用程序恢復到正常操作壹罚。即使當前窗口大小為 0,也是可以發(fā)送緊急數(shù)據(jù)的寿羞,因為緊急數(shù)據(jù)無須緩存猖凛。
可選項字段
選項(Option):長度不定,但長度必須是 32bits 的整數(shù)倍绪穆。
TCP建立連接
TCP建立連接需要三個步驟辨泳,也就是大家熟知的三次握手。下圖了正常情形下通過三次握手建立連接的過程:
A機器發(fā)出一個數(shù)據(jù)包
SYN
設置為1玖院,表示希望建立連接菠红。這個包中的假設seq為x
。機器A發(fā)送
SYN
數(shù)據(jù)包后难菌,會進入SYN_SENT
狀態(tài)B機器收到A發(fā)送的
SYN
數(shù)據(jù)后试溯,響應一個數(shù)據(jù)包將SYN
和ACK
設置為1,假設這個響應包的序列號為y
郊酒,同時期望下一次收到的數(shù)據(jù)庫的序列為x+1
B回復響應包后遇绞,進入
SYN_RECD
狀態(tài)A收到B的響應包后,對響應包做應答將
ACK
標志設置為1燎窘,序列號為x + 1
摹闽,期望下一次收到的數(shù)據(jù)包的序列號為y+1
A機器和B機器連接建立成功
TCP三次握手抓包驗證
以為驗證三次握手是否描述正確,在下使用Wireshark
進行抓包驗證荠耽。首先使用ping
命令獲取www.baidu.com
的ip地址:
正在 Ping www.a.shifen.com [183.232.231.174] 具有 32 字節(jié)的數(shù)據(jù):
來自 183.232.231.174 的回復: 字節(jié)=32 時間=16ms TTL=54
來自 183.232.231.174 的回復: 字節(jié)=32 時間=16ms TTL=54
來自 183.232.231.174 的回復: 字節(jié)=32 時間=16ms TTL=54
183.232.231.172 的 Ping 統(tǒng)計信息:
數(shù)據(jù)包: 已發(fā)送 = 3钩骇,已接收 = 3,丟失 = 0 (0% 丟失)铝量,
往返行程的估計時間(以毫秒為單位):
最短 = 16ms倘屹,最長 = 16ms,平均 = 16ms
以上輸出顯示www.baidu.com
的ip地址:183.232.231.174
慢叨,然后使用Wireshark
的過濾器僅顯示與www.baidu.com
通信的tcp
數(shù)據(jù)包:
ip.src_host == "183.232.231.174" or ip.dst_host == "183.232.231.174" and tcp
使用Wireshark
抓包分析后纽匙,驗證TCP正常連接三次握手與上節(jié)描述的一致。
為什么是三次握手拍谐?
為什么是三次握手烛缔?三次握手主要有兩個目的:信息對等和防止超時。
信息對等
兩臺機器通信時都需要確認四個信息:
自己發(fā)報文的能力
自己收報文的能力
對方發(fā)報文的能力
對方收報文的通知
第一次握手
第一次握手A機器向B機器發(fā)送SYN
數(shù)據(jù)包轩拨,此時只有B機器能確認自己收報文的能力和對方發(fā)報文的能力践瓷。
一次握手完成B機器能夠確認的信息有:
√B機器收報文的能力
√A機器發(fā)報文的能力
第二次握手
每二次握手后B響應A機器的SYN
數(shù)據(jù)包,此時A機器就能確認:自己發(fā)報文的能力亡蓉、自己收報文的能力晕翠、對方發(fā)報文的能力、對方收報文的能力
二次握手完成A機器能夠確認的信息有:
√A機器發(fā)報文的能力
√A機器收報文的能力
√B機器發(fā)報文的能力
√B機器收報文的能力
第三次握手
每三次握手后A應答B(yǎng)機器的SYN + ACK
數(shù)據(jù)包,此時B機器就能確認:自己發(fā)報文的能力淋肾、對方收報文的能力
三次握手完成B機器能夠確認的信息有:
√B機器發(fā)報文的能力
√A機器收報文的能力
至此經(jīng)過三次握手A硫麻、B機器就能做到信息對等,雙方都能確認自己和對方的收樊卓、發(fā)報文的能力拿愧,最后方便理解將信息對等制作成一個小表格:
防止超時
三次握手除了保證信息對等也是了防止請求超時導致臟連接。TTL網(wǎng)絡報文的生存往往會超過TCP請求超時時間碌尔,如果兩次握手就能創(chuàng)建連接浇辜,傳輸數(shù)據(jù)并釋放連接后,第一個超時的連接請求才到達B機器七扰,B機器 會以為是 A 創(chuàng)建新連接的請求奢赂,然后確認同意創(chuàng)建連接陪白。因為A機器的狀態(tài)不是SYN_SENT
颈走,所以會直接丟棄了B的確認數(shù)據(jù),導致 B 機器單方面的創(chuàng)建連接完畢咱士。
如果是三次握手立由,則 B 機器收到連接請求后,同樣會向 A 機器確同意創(chuàng)建連接序厉,但因為 A 不是SYN_SENT
狀態(tài)锐膜,所以 A機器 不會回復 B 機器確認創(chuàng)建連接請求,而 B 機器到一段時間后由于長時間沒有收到確認信息弛房,最終會導致連接創(chuàng)建失敗道盏,因此不會出現(xiàn)臟連接。
TCP斷開連接
TCP是全雙工通信文捶,雙方都能作為數(shù)據(jù)的發(fā)送方和接收方荷逞,但TCP會有斷開的時候。TCP建立連接需要三次握手而斷開連接卻要四次粹排,如圖所示為TCP斷開連接四次揮手過程:
A 機器發(fā)送關閉數(shù)據(jù)包將
FIN
設置為1种远,假設序列號為u
,發(fā)完關閉數(shù)據(jù)包后此時 A 機器處理FIN_WAIT_1
狀態(tài)B 收到關閉連接請求后顽耳,通知應用程序處理完剩下的數(shù)據(jù)
B 響應 A 的關閉連接請求坠敷,將
ACK
標志設置為1,seq為v
射富,ack為u+1
膝迎,隨后 B 機器處于CLOSE_WAIT
狀態(tài)A 收到應答后,處于
FIN_WAIT_2
狀態(tài)胰耗,繼續(xù)等待 B 機器的FIN
數(shù)據(jù)包B 處理好現(xiàn)場后限次,主動向 A 機器發(fā)送數(shù)據(jù)包,并將
FIN
和ACK
標志設置為1宪郊,seq為w
掂恕,ack為u+1
拖陆,隨后處于LAST_WAIT
狀態(tài)等待 A 機器的應答A 機器收到
FIN
數(shù)據(jù)包后,隨后發(fā)送ACK
數(shù)據(jù)包懊亡,seq為u+1
,ack為w+1
, 此時 A 機器處理TIME_WAIT
狀態(tài)B 機器收到
ACK
響應包后依啰,進行CLOSED
狀態(tài),連接正常關閉A 機器在
TIME_WAIT
狀態(tài)等待2MSL
后店枣,也進入CLOSEED
狀態(tài)速警,連接關閉
什么是2MSL:MSL是Maximum Segment Lifetime英文的縮寫,中文可以譯為“報文最大生存時間”鸯两,
2MSL即兩倍的MSL
四次揮手斷開連接可以用更形象的方式來表達:
男生 :我們分手吧闷旧。
女生 :好的,我需要去家里把東西收拾完钧唐,再發(fā)消息給你忙灼。(此時男生不能再擁抱女生)
。钝侠。该园。,一個小時后
女生 :我收拾完了帅韧,分手吧(此時女生也不能再擁抱男生)
男生:好的(此時雙方約定一段時間后里初,才可以分別找新的對象)
TCP四次揮手抓包驗證
抓包過程與與三次握手抓包過程一致,這里不描述忽舟。直接看訪問后抓包的截圖:
第一個包是由
192.168.1.6
這臺機器(也就是客戶機)双妨,發(fā)送了一個FIN
包,seq為80
,ack為2782
第二個包由
183.232.231.174
(服務器)叮阅,對192.168.1.6
這臺機器(也就是客戶機)發(fā)送了一個ACK
包刁品,seq為2782
,ack為81
第三個包由
183.232.231.174
(服務器)帘饶,對192.168.1.6
這臺機器(也就是客戶機)發(fā)送了一個ACK
和FIN
包哑诊,seq為2782
,ack為81
第四個包由
192.168.1.6
及刻,向服務器響應了一個ACK
包镀裤,seq為81
,ack為2783
四次揮手流程與我們描述的一致缴饭。
TIME_WAIT 狀態(tài)
主動要求關閉的機器(機器A)表示收到對方的FIN
報文后暑劝,并發(fā)送出ACK
報文后,進行TIME_WAIT
狀態(tài)颗搂,等待2MSL
后進行CLOSED
狀態(tài)担猛。如果在TIME_WAIT_1
時收到FIN
標志和ACK
標志報文時,可以直接進入TIME_WAIT
狀態(tài),而無需進入TIME_WAIT_2
狀態(tài)傅联。
為什么要有 TIME_WAIT
確認被動關閉(機器B)能夠順利進入CLOSED
狀態(tài)
假如A機器發(fā)送最后一個ACK
后先改,但由于網(wǎng)絡原因ACK
包未能到達 B 機器,此時 B機器通常會認為 A機器 沒有收到 FIN+ACK
報文蒸走,會重發(fā)一次FIN+ACK
報文仇奶。如果 A機器 發(fā)送最后一個ACK
后,自私的關閉連接進入 CLOSED
狀態(tài)比驻,就可能導致 B 無法收到ACK
報文该溯,無法正常關閉。
防止失效請求
TIME_WAIT 狀態(tài)可以防止已失效的請求包與正常連接的請求數(shù)據(jù)包混淆而發(fā)生異常别惦。因為TIME_WAIT 狀態(tài)無法真正釋放句柄資源狈茉,在此期間, Socket中使用的本地端口在默認情況下不能再被使用掸掸。
CLOSE_WAIT 狀態(tài)
被動關閉的機器(機器B)在收到對方發(fā)送的氯庆,FIN
報文后,馬上回復ACK
報文猾漫,進入CLOSE_WAIT
狀態(tài)点晴。通知應用程序,處理剩下的數(shù)據(jù)悯周,釋放資源。