TCP協(xié)議全稱為: Transmission Control Protocol 妥泉,是一種面向鏈接盲链、保證數(shù)據(jù)傳輸安全刽沾、可靠的數(shù)據(jù)傳輸協(xié)議侧漓。為了確保數(shù)據(jù)的可靠傳輸火架,不僅需要對(duì)發(fā)出的每個(gè)字節(jié)進(jìn)行編號(hào)確認(rèn)何鸡,還需要驗(yàn)證每一個(gè)數(shù)據(jù)包的有效性骡男。每個(gè)TCP數(shù)據(jù)包是封閉在IP包中的隔盛,每個(gè)一IP包的后面緊跟著的是TCP頭吮炕,TCP報(bào)文格式如下:
源端口和目的端口字段
- TCP源端口(Source Port):源計(jì)算機(jī)上的應(yīng)用程序的端口號(hào)悍抑,占 16 位拂盯。
- TCP目的端口(Destination Port):目標(biāo)計(jì)算機(jī)的應(yīng)用程序端口號(hào)谈竿,占 16 位榕订。
序列號(hào)字段
CP序列號(hào)(Sequence Number):占 32 位劫恒。它表示本報(bào)文段所發(fā)送數(shù)據(jù)的第一個(gè)字節(jié)的編號(hào)两嘴。在 TCP 連接中憔辫,所傳送的字節(jié)流的每一個(gè)字節(jié)都會(huì)按順序編號(hào)贰您。當(dāng)SYN標(biāo)記不為1時(shí)锦亦,這是當(dāng)前數(shù)據(jù)分段第一個(gè)字母的序列號(hào)杠园;如果SYN的值是1時(shí)抛蚁,這個(gè)字段的值就是初始序列值(ISN)瞧甩,用于對(duì)序列號(hào)進(jìn)行同步爷辙。這時(shí)犬钢,第一個(gè)字節(jié)的序列號(hào)比這個(gè)字段的值大1玷犹,也就是ISN加1歹颓。
確認(rèn)號(hào)字段
TCP 確認(rèn)號(hào)(Acknowledgment Number巍扛,ACK Number):占 32 位撤奸。它表示接收方期望收到發(fā)送方下一個(gè)報(bào)文段的第一個(gè)字節(jié)數(shù)據(jù)的編號(hào)胧瓜。其值是接收計(jì)算機(jī)即將接收到的下一個(gè)序列號(hào)府喳,也就是下一個(gè)接收到的字節(jié)的序列號(hào)加1钝满。
數(shù)據(jù)偏移字段
TCP 首部長(zhǎng)度(Header Length):數(shù)據(jù)偏移是指數(shù)據(jù)段中的“數(shù)據(jù)”部分起始處距離 TCP 數(shù)據(jù)段起始處的字節(jié)偏移量弯蚜,占 4 位熟吏。其實(shí)這里的“數(shù)據(jù)偏移”也是在確定 TCP 數(shù)據(jù)段頭部分的長(zhǎng)度牵寺,告訴接收端的應(yīng)用程序帽氓,數(shù)據(jù)從何處開始俩块。
保留字段
保留(Reserved):占 4 位玉凯。為 TCP 將來的發(fā)展預(yù)留空間捎拯,目前必須全部為 0盲厌。
標(biāo)志位字段
- CWR(Congestion Window Reduce):擁塞窗口減少標(biāo)志建芙,用來表明它接收到了設(shè)置 ECE 標(biāo)志的 TCP 包懂扼。并且阀湿,發(fā)送方收到消息之后钧大,通過減小發(fā)送窗口的大小來降低發(fā)送速率罩旋。
- ECE(ECN Echo):用來在 TCP 三次握手時(shí)表明一個(gè) TCP 端是具備 ECN 功能的。在數(shù)據(jù)傳輸過程中逝撬,它也用來表明接收到的 TCP 包的 IP 頭部的 ECN 被設(shè)置為 11宪潮,即網(wǎng)絡(luò)線路擁堵狡相。
- URG(Urgent):表示本報(bào)文段中發(fā)送的數(shù)據(jù)是否包含緊急數(shù)據(jù)尽棕。URG=1 時(shí)表示有緊急數(shù)據(jù)。當(dāng) URG=1 時(shí)单绑,后面的緊急指針字段才有效搂橙。
- ACK:表示前面的確認(rèn)號(hào)字段是否有效份氧。ACK=1 時(shí)表示有效蜗帜。只有當(dāng) ACK=1 時(shí)厅缺,前面的確認(rèn)號(hào)字段才有效。TCP 規(guī)定诀豁,連接建立后舷胜,ACK 必須為 1烹骨。
- PSH(Push):告訴對(duì)方收到該報(bào)文段后是否立即把數(shù)據(jù)推送給上層吨岭。如果值為 1峦树,表示應(yīng)當(dāng)立即把數(shù)據(jù)提交給上層急灭,而不是緩存起來化戳。
- RST:表示是否重置連接。如果 RST=1白对,說明 TCP 連接出現(xiàn)了嚴(yán)重錯(cuò)誤(如主機(jī)崩潰)甩恼,必須釋放連接条摸,然后再重新建立連接钉蒲。
- SYN:在建立連接時(shí)使用顷啼,用來同步序號(hào)。當(dāng) SYN=1间驮,ACK=0 時(shí)扛施,表示這是一個(gè)請(qǐng)求建立連接的報(bào)文段;當(dāng) SYN=1笛谦,ACK=1 時(shí)饥脑,表示對(duì)方同意建立連接懦冰。SYN=1 時(shí)刷钢,說明這是一個(gè)請(qǐng)求建立連接或同意建立連接的報(bào)文内地。只有在前兩次握手中 SYN才為 1阱缓。
- FIN:標(biāo)記數(shù)據(jù)是否發(fā)送完畢非凌。如果 FIN=1,表示數(shù)據(jù)已經(jīng)發(fā)送完成荆针,可以釋放連接敞嗡。
窗口大小字段
窗口大小(Window Size):占 16 位航背。它表示從 Ack Number 開始還可以接收多少字節(jié)的數(shù)據(jù)量喉悴,也表示當(dāng)前接收端的接收窗口還有多少剩余空間。該字段可以用于 TCP 的流量控制玖媚。
TCP 校驗(yàn)和字段
校驗(yàn)位(TCP Checksum):占 16 位箕肃。它用于確認(rèn)傳輸?shù)臄?shù)據(jù)是否有損壞涡贱。發(fā)送端基于數(shù)據(jù)內(nèi)容校驗(yàn)生成一個(gè)數(shù)值,接收端根據(jù)接收的數(shù)據(jù)校驗(yàn)生成一個(gè)值。兩個(gè)值必須相同,才能證明數(shù)據(jù)是有效的。如果兩個(gè)值不同,則丟掉這個(gè)數(shù)據(jù)包须妻。Checksum 是根據(jù)偽頭 + TCP 頭 + TCP 數(shù)據(jù)三部分進(jìn)行計(jì)算的。
緊急指針字段
緊急指針(Urgent Pointer):僅當(dāng)前面的 URG 控制位為 1 時(shí)才有意義。它指出本數(shù)據(jù)段中為緊急數(shù)據(jù)的字節(jié)數(shù),占 16 位。當(dāng)所有緊急數(shù)據(jù)處理完后杰赛,TCP 就會(huì)告訴應(yīng)用程序恢復(fù)到正常操作蛤迎。即使當(dāng)前窗口大小為 0扎唾,也是可以發(fā)送緊急數(shù)據(jù)的,因?yàn)榫o急數(shù)據(jù)無須緩存逗威。
可選項(xiàng)字段
選項(xiàng)(Option):長(zhǎng)度不定鞠柄,但長(zhǎng)度必須是 32bits 的整數(shù)倍。
TCP建立連接
TCP建立連接需要三個(gè)步驟,也就是大家熟知的三次握手。下圖了正常情形下通過三次握手建立連接的過程:
- A機(jī)器發(fā)出一個(gè)數(shù)據(jù)包 SYN 設(shè)置為1,表示希望建立連接。這個(gè)包中的假設(shè)seq為 x北秽。機(jī)器A發(fā)送 SYN 數(shù)據(jù)包后,會(huì)進(jìn)入 SYN_SENT 狀態(tài)
- B機(jī)器收到A發(fā)送的 SYN 數(shù)據(jù)后,響應(yīng)一個(gè)數(shù)據(jù)包將 SYN 和 ACK 設(shè)置為1毁渗,假設(shè)這個(gè)響應(yīng)包的序列號(hào)為 y 疟暖,同時(shí)期望下一次收到的數(shù)據(jù)庫(kù)的序列為 x+1B回復(fù)響應(yīng)包后,進(jìn)入 SYN_RECD 狀態(tài)
- A收到B的響應(yīng)包后,對(duì)響應(yīng)包做應(yīng)答將 ACK 標(biāo)志設(shè)置為1夭坪,序列號(hào)為 x + 1 ,期望下一次收到的數(shù)據(jù)包的序列號(hào)為 y+1A機(jī)器和B機(jī)器連接建立成功
TCP三次握手抓包驗(yàn)證
以為驗(yàn)證三次握手是否描述正確迅矛,在下使用 Wireshark 進(jìn)行抓包驗(yàn)證。首先使用 ping 命令獲取 www.baidu.com 的ip地址:
正在 Ping www.a.shifen.com [183.232.231.174] 具有 32 字節(jié)的數(shù)據(jù):來自 183.232.231.174 的回復(fù): 字節(jié)=32 時(shí)間=16ms TTL=54來自 183.232.231.174 的回復(fù): 字節(jié)=32 時(shí)間=16ms TTL=54來自 183.232.231.174 的回復(fù): 字節(jié)=32 時(shí)間=16ms TTL=54183.232.231.172 的 Ping 統(tǒng)計(jì)信息: 數(shù)據(jù)包: 已發(fā)送 = 3侥加,已接收 = 3,丟失 = 0 (0% 丟失),往返行程的估計(jì)時(shí)間(以毫秒為單位): 最短 = 16ms币砂,最長(zhǎng) = 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 抓包分析后曹鸠,驗(yàn)證TCP正常連接三次握手與上節(jié)描述的一致耗溜。
為什么是三次握手蟀俊?
為什么是三次握手钦铺?三次握手主要有兩個(gè)目的: 信息對(duì)等 和 防止超時(shí) 。
信息對(duì)等
兩臺(tái)機(jī)器通信時(shí)都需要確認(rèn)四個(gè)信息:
- 自己發(fā)報(bào)文的能力
- 自己收?qǐng)?bào)文的能力
- 對(duì)方發(fā)報(bào)文的能力
- 對(duì)方收?qǐng)?bào)文的通知
第一次握手
第一次握手A機(jī)器向B機(jī)器發(fā)送 SYN 數(shù)據(jù)包欧漱,此時(shí)只有B機(jī)器能確認(rèn) 自己收?qǐng)?bào)文的能力 和 對(duì)方發(fā)報(bào)文的能力 职抡。
一次握手完成B機(jī)器能夠確認(rèn)的信息有:
- B機(jī)器收?qǐng)?bào)文的能力
- A機(jī)器發(fā)報(bào)文的能力
第二次握手
每二次握手后B響應(yīng)A機(jī)器的 SYN 數(shù)據(jù)包,此時(shí)A機(jī)器就能確認(rèn): 自己發(fā)報(bào)文的能力 误甚、 自己收?qǐng)?bào)文的能力 缚甩、 對(duì)方發(fā)報(bào)文的能力 、 對(duì)方收?qǐng)?bào)文的能力
二次握手完成A機(jī)器能夠確認(rèn)的信息有:
- A機(jī)器發(fā)報(bào)文的能力
- A機(jī)器收?qǐng)?bào)文的能力
- B機(jī)器發(fā)報(bào)文的能力
- B機(jī)器收?qǐng)?bào)文的能力
第三次握手
每三次握手后A應(yīng)答B(yǎng)機(jī)器的 SYN + ACK 數(shù)據(jù)包窑邦,此時(shí)B機(jī)器就能確認(rèn): 自己發(fā)報(bào)文的能力 擅威、 對(duì)方收?qǐng)?bào)文的能力
二次握手完成A機(jī)器能夠確認(rèn)的信息有:
- B機(jī)器發(fā)報(bào)文的能力
- A機(jī)器收?qǐng)?bào)文的能力
至此經(jīng)過三次握手A、B機(jī)器就能做到信息對(duì)等冈钦,雙方都能確認(rèn)自己和對(duì)方的收郊丛、發(fā)報(bào)文的能力,最后方便理解將信息對(duì)等制作成一個(gè)小表格:
防止超時(shí)
三次握手除了保證 信息對(duì)等 也是了防止請(qǐng)求超時(shí)導(dǎo)致 臟連接 厉熟。TTL網(wǎng)絡(luò)報(bào)文的生存往往會(huì)超過TCP請(qǐng)求超時(shí)時(shí)間,如果兩次握手就能創(chuàng)建連接较幌,傳輸數(shù)據(jù)并釋放連接后揍瑟,第一個(gè)超時(shí)的連接請(qǐng)求才到達(dá)B機(jī)器,B機(jī)器 會(huì)以為是 A 創(chuàng)建新連接的請(qǐng)求乍炉,然后確認(rèn)同意創(chuàng)建連接绢片。因?yàn)锳機(jī)器的狀態(tài)不是 SYN_SENT ,所以會(huì)直接丟棄了B的確認(rèn)數(shù)據(jù)岛琼,導(dǎo)致 B 機(jī)器單方面的創(chuàng)建連接完畢底循。
如果是三次握手槐瑞,則 B 機(jī)器收到連接請(qǐng)求后熙涤,同樣會(huì)向 A 機(jī)器確同意創(chuàng)建連接,但因?yàn)?A 不是 SYN_SENT 狀態(tài),所以 A機(jī)器 不會(huì)回復(fù) B 機(jī)器確認(rèn)創(chuàng)建連接請(qǐng)求灭袁,而 B 機(jī)器到一段時(shí)間后由于長(zhǎng)時(shí)間沒有收到確認(rèn)信息猬错,最終會(huì)導(dǎo)致連接創(chuàng)建失敗,因此不會(huì)出現(xiàn)臟連接茸歧。
TCP斷開連接
TCP是全雙工通信,雙方都能作為數(shù)據(jù)的發(fā)送方和接收方显沈,但TCP會(huì)有斷開的時(shí)候软瞎。TCP建立連接需要三次握手而斷開連接卻要四次,如圖所示為TCP斷開連接四次揮手過程:
- A 機(jī)器發(fā)送關(guān)閉數(shù)據(jù)包將 FIN 設(shè)置為1涤浇,假設(shè)序列號(hào)為 u ,發(fā)完關(guān)閉數(shù)據(jù)包后此時(shí) A 機(jī)器處理 FIN_WAIT_1 狀態(tài)
- B 收到關(guān)閉連接請(qǐng)求后魔慷,通知應(yīng)用程序處理完剩下的數(shù)據(jù)
- B 響應(yīng) A 的關(guān)閉連接請(qǐng)求只锭,將 ACK 標(biāo)志設(shè)置為1,seq為 v 院尔,ack為 u+1 蜻展,隨后 B 機(jī)器處于 CLOSE_WAIT 狀態(tài)
- A 收到應(yīng)答后,處于 FIN_WAIT_2 狀態(tài)邀摆,繼續(xù)等待 B 機(jī)器的 FIN 數(shù)據(jù)包
- B 處理好現(xiàn)場(chǎng)后纵顾,主動(dòng)向 A 機(jī)器發(fā)送數(shù)據(jù)包,并將 FIN 和 ACK 標(biāo)志設(shè)置為1栋盹,seq為 w 施逾,ack為 u+1 ,隨后處于 LAST_WAIT 狀態(tài)等待 A 機(jī)器的應(yīng)答
- A 機(jī)器收到 FIN 數(shù)據(jù)包后例获,隨后發(fā)送 ACK 數(shù)據(jù)包汉额,seq為 u+1 ,ack為 w+1 , 此時(shí) A 機(jī)器處理 TIME_WAIT 狀態(tài)
- B 機(jī)器收到 ACK 響應(yīng)包后,進(jìn)行 CLOSED 狀態(tài)榨汤,連接正常關(guān)閉
- A 機(jī)器在 TIME_WAIT 狀態(tài)等待 2MSL 后蠕搜,也進(jìn)入 CLOSEED 狀態(tài),連接關(guān)閉什么是2MSL :MSL是Maximum Segment Lifetime英文的縮寫件余,中文可以譯為“報(bào)文最大生存時(shí)間”讥脐,
2MSL即兩倍的MSL
四次揮手?jǐn)嚅_連接可以用更形象的方式來表達(dá):
- 男生 :我們分手吧。
- 女生 :好的啼器,我需要去家里把東西收拾完旬渠,再發(fā)消息給你。(此時(shí)男生不能再擁抱女生)
- 端壳。告丢。。损谦,一個(gè)小時(shí)后
- 女生 :我收拾完了岖免,分手吧(此時(shí)女生也不能再擁抱男生)
- 男生:好的(此時(shí)雙方約定一段時(shí)間后岳颇,才可以分別找新的對(duì)象)
TCP四次揮手抓包驗(yàn)證
抓包過程與與三次握手抓包過程一致,這里不描述颅湘。直接看訪問后抓包的截圖:
- 第一個(gè)包是由 192.168.1.6 這臺(tái)機(jī)器(也就是客戶機(jī)),發(fā)送了一個(gè) FIN 包闯参,seq為 80 ,ack為 2782
- 第二個(gè)包由 183.232.231.174 (服務(wù)器)瞻鹏,對(duì) 192.168.1.6 這臺(tái)機(jī)器(也就是客戶機(jī))發(fā)送了一個(gè) ACK 包,seq為 2782 鹿寨,ack為 81
- 第三個(gè)包由 183.232.231.174 (服務(wù)器)新博,對(duì) 192.168.1.6 這臺(tái)機(jī)器(也就是客戶機(jī))發(fā)送了一個(gè) ACK 和 FIN 包脚草,seq為 2782 ,ack為 81
- 第四個(gè)包由 192.168.1.6 馏慨,向服務(wù)器響應(yīng)了一個(gè) ACK 包,seq為 81 熏纯,ack為 2783
四次揮手流程與我們描述的一致同诫。
TIME_WAIT 狀態(tài)
主動(dòng)要求關(guān)閉的機(jī)器(機(jī)器A)表示收到對(duì)方的 FIN 報(bào)文后樟澜,并發(fā)送出 ACK 報(bào)文后,進(jìn)行 TIME_WAIT 狀態(tài)秩贰,等待 2MSL 后進(jìn)行 CLOSED 狀態(tài)霹俺。如果在 TIME_WAIT_1 時(shí)收到 FIN 標(biāo)志和 ACK 標(biāo)志報(bào)文時(shí),可以直接進(jìn)入 TIME_WAIT 狀態(tài)毒费,而無需進(jìn)入 TIME_WAIT_2 狀態(tài)丙唧。
為什么要有 TIME_WAIT
確認(rèn)被動(dòng)關(guān)閉(機(jī)器B)能夠順利進(jìn)入 CLOSED 狀態(tài)
假如A機(jī)器發(fā)送最后一個(gè) ACK 后想际,但由于網(wǎng)絡(luò)原因 ACK 包未能到達(dá) B 機(jī)器溪厘,此時(shí) B機(jī)器通常會(huì)認(rèn)為 A機(jī)器 沒有收到 FIN+ACK 報(bào)文,會(huì)重發(fā)一次 FIN+ACK 報(bào)文畸悬。如果 A機(jī)器 發(fā)送最后一個(gè) ACK 后,自私的關(guān)閉連接進(jìn)入 CLOSED 狀態(tài)披粟,就可能導(dǎo)致 B 無法收到 ACK 報(bào)文,無法正常關(guān)閉惑艇。
防止失效請(qǐng)求
TIME_WAIT 狀態(tài)可以防止已失效的請(qǐng)求包與正常連接的請(qǐng)求數(shù)據(jù)包混淆而發(fā)生異常胸梆。因?yàn)門IME_WAIT 狀態(tài)無法真正釋放句柄資源,在此期間, Socket中使用的本地端口在默認(rèn)情況下不能再被使用习瑰。
CLOSE_WAIT 狀態(tài)
被動(dòng)關(guān)閉的機(jī)器(機(jī)器B)在收到對(duì)方發(fā)送的, FIN 報(bào)文后柠横,馬上回復(fù) ACK 報(bào)文课兄,進(jìn)入 CLOSE_WAIT 狀態(tài)。通知應(yīng)用程序搬俊,處理剩下的數(shù)據(jù)蜒茄,釋放資源。
好了玩祟,如果這篇文章對(duì)你有幫助的話屿聋,請(qǐng)幫我點(diǎn)個(gè)贊,感謝转锈!