1 TCP三次握手四次揮手
TCP 在傳輸之前會進(jìn)行三次溝通,一般稱為三次握手,傳完數(shù)據(jù)斷開的時(shí)候要進(jìn)行四次揮手
1.1 數(shù)據(jù)包說明
1.1.1 TCP數(shù)據(jù)包

數(shù)據(jù)包說明:
-
源端口號(16 位):它(連同源主機(jī) IP 地址)標(biāo)識源主機(jī)的一個(gè)應(yīng)用進(jìn)程 -
目的端口號(16 位):它(連同目的主機(jī) IP 地址)標(biāo)識目的主機(jī)的一個(gè)應(yīng)用進(jìn)程。這兩個(gè)值加上 IP 報(bào)頭中的源主機(jī) IP 地址和目的主機(jī) IP 地址確定唯一一個(gè) TCP 連接 -
順序號seq(32 位): 用來標(biāo)識從TCP源端向TCP目的端發(fā)送的數(shù)據(jù)字節(jié)流,它表示在這個(gè)報(bào)文段中的第一個(gè)數(shù)據(jù)字節(jié)的順序號。如果將字節(jié)流看作在兩個(gè)應(yīng)用程序間的單向流動,則TCP用順序號對每個(gè)字節(jié)進(jìn)行計(jì)數(shù)。序號是32bit的無符號數(shù), 序號到達(dá)2^32-1后又從 0 開始。 當(dāng)建立一個(gè)新的連接時(shí),SYN標(biāo)志變1,順序號字段包含 由這個(gè)主機(jī)選擇的 該連接的初始順序號ISN (Initial Sequence Number ) -
確認(rèn)號 ack(32 位): 包含發(fā)送確認(rèn)的一端所期望收到的下一個(gè)順序號。因此,確認(rèn)序號應(yīng)當(dāng)是上次已成功收到數(shù)據(jù)字節(jié)順序號加 1。 只有ACK標(biāo)志為 1 時(shí)確認(rèn)序號字段才有效。
TCP為應(yīng)用層提供全雙工服務(wù),這意味數(shù)據(jù)能在兩個(gè)方向上獨(dú)立地進(jìn)行傳輸。因此,連接的每一端必須保持每個(gè)方向上的傳輸數(shù)據(jù)順序號。 -
TCP報(bào)頭長度(4 位):給出報(bào)頭中32bit字的數(shù)目, 它實(shí)際上指明數(shù)據(jù)從哪里開始。 需要這個(gè)值是因?yàn)槿芜x字段的長度是可變的。這個(gè)字段占4bit,因此TCP最多有 60 字節(jié)的首部。然而,沒有任選字段,正常的長度是20字節(jié) -
保留位(6 位):保留給將來使用,目前必須置為 0 。 -
控制位(control flags, 6 位):在TCP報(bào)頭中有 6 個(gè)標(biāo)志比特,它們中的多個(gè)可同時(shí)被設(shè)置為 1 。依次為:
URG:為 1 表示緊急指針有效,為 0 則忽略緊急指針值。
ACK:為 1 表示確認(rèn)號有效,為 0 表示報(bào)文中不包含確認(rèn)信息,忽略確認(rèn)號字段。
PSH:為 1 表示是帶有PUSH標(biāo)志的數(shù)據(jù), 指示接收方應(yīng)該盡快將這個(gè)報(bào)文段交給應(yīng)用層而不用等待緩沖區(qū)裝滿。
RST: 用于復(fù)位由于主機(jī)崩潰或其他原因而出現(xiàn)錯(cuò)誤的連接。它還可以用于拒絕非法的報(bào)文段和拒絕連接請求。一般情況下,如果收到一個(gè)RST為 1 的報(bào)文,那么一定發(fā)生了某些問題。
SYN:同步序號, 為 1 表示連接請求,用于建立連接和使順序號同步synchronize
FIN: 用于釋放連接,為 1 表示發(fā)送方已經(jīng)沒有數(shù)據(jù)發(fā)送了,即關(guān)閉本方數(shù)據(jù)流。 -
窗口大小(16 位):數(shù)據(jù)字節(jié)數(shù),表示從確認(rèn)號開始,本報(bào)文的源方可以接收的字節(jié)數(shù),即源方接收窗口大小。窗口大小是一個(gè)16bit字段,因而窗口大小最大為65535字節(jié)。 -
校驗(yàn)和(16 位):此校驗(yàn)和是對整個(gè)的TCP報(bào)文段, 包括TCP頭部和TCP數(shù)據(jù),以 16 位字進(jìn)行計(jì)算所得。這是一個(gè)強(qiáng)制性的字段,一定是由發(fā)送端計(jì)算和存儲, 并由接收端進(jìn)行驗(yàn)證。 -
緊急指針(16 位):只有當(dāng)URG標(biāo)志置 1 時(shí)緊急指針才有效。TCP的緊急方式是發(fā)送端向另一端發(fā)送緊急數(shù)據(jù)的一種方式 -
選項(xiàng):最常見的可選字段是最長報(bào)文大小,又稱為MSS(Maximum Segment Size)。每個(gè)連接方通常都在通信的第一個(gè)報(bào)文段(為建立連接而設(shè)置 SYN 標(biāo)志的那個(gè)段)中指明這個(gè)選項(xiàng),它指明本端所能接收的最大長度的報(bào)文段。選項(xiàng)長度不一定是 32 位字的整數(shù)倍,所以要加填充位,使得報(bào)頭長度成為整字?jǐn)?shù)。 -
數(shù)據(jù):TCP報(bào)文段中的數(shù)據(jù)部分是可選的。在一個(gè)連接建立和一個(gè)連接終止時(shí),雙方交換的報(bào)文段僅有 TCP 首部。如果一方?jīng)]有數(shù)據(jù)要發(fā)送,也使用沒有任何數(shù)據(jù)的首部來確認(rèn)收到的數(shù)據(jù)。在處理超時(shí)的許多情況中,也會發(fā)送不帶任何數(shù)據(jù)的報(bào)文段
1.1.2 UDP數(shù)據(jù)包

-
源端口號(Source Port):這個(gè)字段占據(jù)UDP報(bào)文頭的前 16 位,通常包含發(fā)送數(shù)據(jù)報(bào)的應(yīng)用程序所使用的UDP端口。接收端的應(yīng)用程序利用這個(gè)字段的值作為發(fā)送響應(yīng)的目的地址。這個(gè)字段是可選項(xiàng),有時(shí)不會設(shè)置源端口號。沒有源端口號就默認(rèn)為 0 ,通常用于不需要返回消息的通信中。 -
目標(biāo)端口號(Destination Port): 表示接收端端口,字段長為 16 位。 -
長度(Length): 該字段占據(jù) 16 位,表示 UDP 數(shù)據(jù)報(bào)長度,包含 UDP 報(bào)文頭和 UDP 數(shù)據(jù)長度。因?yàn)?UDP 報(bào)文頭長度是 8 個(gè)字節(jié),所以這個(gè)值最小為 8,最大長度為2 ^ 16 = 65535字節(jié)(即報(bào)文長度為64K) -
校驗(yàn)和(Checksum):UDP使用校驗(yàn)和來保證數(shù)據(jù)安全性,UDP的校驗(yàn)和也提供了差錯(cuò)檢測功能,差錯(cuò)檢測用于校驗(yàn)報(bào)文段從源到目標(biāo)主機(jī)的過程中,數(shù)據(jù)的完整性是否發(fā)生了改變
轉(zhuǎn)載于:https://mp.weixin.qq.com/s/aAAZQh8r7eCsIR9GsSvauw
1.1.3 TCP和UDP差異
- UDP 沒有所謂的序列號和確認(rèn)號,所以不會對數(shù)據(jù)進(jìn)行確認(rèn),數(shù)據(jù)丟失后也不會進(jìn)行重傳,所以 UDP 是一種不可靠的協(xié)議
- TCP具有高可靠性,確保傳輸數(shù)據(jù)的正確性,不出現(xiàn)丟失或亂序,傳輸數(shù)據(jù)量大,沒有限制
- TCP相對于UDP速度慢一點(diǎn),效率低,而且要求系統(tǒng)資源較多,每個(gè)連接都會占用系統(tǒng)的CPU、內(nèi)存等硬件資源
- UDP速度快、操作簡單、要求系統(tǒng)資源較少,傳輸數(shù)據(jù)少,理論64K
- UDP不可靠,可能會出現(xiàn)丟包、亂序、數(shù)據(jù)不完整
TCP 協(xié)議:TCP(傳輸控制協(xié)議)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。它在Internet協(xié)議族中是最常用的協(xié)議之一。其主要特點(diǎn)包括:
-
面向連接:在數(shù)據(jù)傳輸之前,TCP需要在發(fā)送端和接收端之間建立一個(gè)連接。這個(gè)過程通常被稱為“三次握手”。 -
可靠性:TCP保證數(shù)據(jù)包的順序和完整性。如果有數(shù)據(jù)丟失或損壞,它會請求重傳。 -
流量控制和擁塞控制:TCP能夠控制數(shù)據(jù)傳輸?shù)乃俾?,以避免網(wǎng)絡(luò)過載。 - 雙向通信:一旦建立連接,數(shù)據(jù)可以在兩個(gè)方向上傳輸。
UDP 協(xié)議:UDP(用戶數(shù)據(jù)報(bào)協(xié)議)是一個(gè)簡單的面向無連接的傳輸層協(xié)議。與TCP相比,UDP具有不同的特點(diǎn):
-
無連接:UDP在傳輸數(shù)據(jù)前不需要建立連接,可以直接發(fā)送數(shù)據(jù)。 -
不保證可靠性:UDP不保證數(shù)據(jù)包的順序、完整性或不重復(fù)。 -
輕量級:UDP頭部開銷小,處理快速,適用于對實(shí)時(shí)性要求高的應(yīng)用,如視頻流、在線游戲。 -
不進(jìn)行流量控制和擁塞控制:它不會調(diào)整發(fā)送速率,可能在網(wǎng)絡(luò)擁堵時(shí)導(dǎo)致數(shù)據(jù)丟失。
TCP和UDP 可以使用同一端口號
對于
TCP和UDP來說,盡管它們作為傳輸層的協(xié)議共享相同的端口號空間,但它們的端口是獨(dú)立管理的。這意味著TCP和UDP可以使用相同的端口號而不會相互沖突。例如,TCP的80端口通常用于HTTP服務(wù),而UDP的80端口可以被另一個(gè)服務(wù)使用,且兩者不會相互干擾。
原因在于TCP和UDP的數(shù)據(jù)包格式中都包含了端口信息,但是由于TCP和UDP是兩個(gè)完全不同的協(xié)議,因此網(wǎng)絡(luò)設(shè)備和操作系統(tǒng)會根據(jù)協(xié)議類型(TCP或UDP)和端口號來正確地處理和路由數(shù)據(jù)。實(shí)際上,在操作系統(tǒng)中,TCP和UDP端口是分別維護(hù)和管理的,因此它們可以獨(dú)立地使用相同的端口號
1.1.4 TCP可靠性傳輸機(jī)制
為了保持 TCP 的可靠性傳輸,TCP 協(xié)議采用了以下機(jī)制:
-
序號與確認(rèn)機(jī)制:TCP使用序號 (sequence number)來對數(shù)據(jù)進(jìn)行編號,并使用確認(rèn)(acknowledgment)來確認(rèn)接收到的數(shù)據(jù)。- 發(fā)送方將每個(gè)數(shù)據(jù)段分配一個(gè)序號,接收方通過發(fā)送確認(rèn)消息(
ACK)來告知發(fā)送方已成功接收到數(shù)據(jù)。如果發(fā)送方在一定時(shí)間內(nèi)沒有收到確認(rèn)消息,就會重新發(fā)送數(shù)據(jù)。 - 當(dāng)接收方拿到數(shù)據(jù)后,知道這段數(shù)據(jù)在整個(gè)字節(jié)流里排
第幾,這樣即使網(wǎng)絡(luò)中途繞路了,后到的數(shù)據(jù)包先來了,TCP也不會立刻把亂序數(shù)據(jù)丟給應(yīng)用,而是先放進(jìn)緩沖區(qū),等前面的補(bǔ)齊,再按順序交付
- 發(fā)送方將每個(gè)數(shù)據(jù)段分配一個(gè)序號,接收方通過發(fā)送確認(rèn)消息(
-
數(shù)據(jù)段校驗(yàn)和:TCP使用校驗(yàn)和(checksum)來檢測數(shù)據(jù)在傳輸過程中是否發(fā)生了錯(cuò)誤。發(fā)送方在發(fā)送數(shù)據(jù)前計(jì)算校驗(yàn)和,并將其附加到數(shù)據(jù)段中。接收方在接收到數(shù)據(jù)后也會計(jì)算校驗(yàn)和,并與發(fā)送方發(fā)送的校驗(yàn)和進(jìn)行比對。如果校驗(yàn)和不匹配,則表明數(shù)據(jù)在傳輸過程中發(fā)生了錯(cuò)誤,接收方會要求發(fā)送方重新發(fā)送數(shù)據(jù)。 -
確認(rèn)重傳機(jī)制:如果發(fā)送方在一定時(shí)間內(nèi)沒有收到確認(rèn)消息,就會認(rèn)為數(shù)據(jù)丟失,并重新發(fā)送數(shù)據(jù)。接收方在收到重復(fù)的數(shù)據(jù)時(shí)會丟棄重復(fù)的數(shù)據(jù),只發(fā)送一個(gè)確認(rèn)消息,以避免重復(fù)處理。- 不是只要沒
ACK就立刻猛重發(fā),因?yàn)?code>網(wǎng)絡(luò)抖動和真正丟包不是一回事,TCP會動態(tài)計(jì)算RTO(重傳超時(shí)時(shí)間),避免太激進(jìn)把網(wǎng)絡(luò)打爆。 - 快速重傳:如果沒超時(shí),但已經(jīng)收到后面的包了,通過
快速重傳能更快知道前面的丟了。
如果接收方如果一直收到比期望序號更大的數(shù)據(jù),就會反復(fù)回相同的 ACK。發(fā)送方看到連續(xù)三個(gè)重復(fù) ACK,基本就能判斷:不是整體網(wǎng)絡(luò)卡住了,而是中間某一段真丟了。那就別等超時(shí)了,直接重傳。
- 不是只要沒
-
滑動窗口機(jī)制:TCP使用滑動窗口(sliding window)機(jī)制來控制發(fā)送方和接收方之間的數(shù)據(jù)流量。發(fā)送方將數(shù)據(jù)分成多個(gè)數(shù)據(jù)段,并將其發(fā)送給接收方。接收方使用滑動窗口來控制可以接收的數(shù)據(jù)量?;瑒哟翱诘拇笮】梢愿鶕?jù)網(wǎng)絡(luò)狀況動態(tài)調(diào)整,以確保數(shù)據(jù)的可靠傳輸。 -
流量控制:TCP使用流量控制機(jī)制來避免發(fā)送方發(fā)送過多的數(shù)據(jù),導(dǎo)致接收方無法處理。接收方可以通過發(fā)送窗口大小告訴發(fā)送方可以接收的數(shù)據(jù)量。發(fā)送方需要根據(jù)接收方的窗口大小來控制發(fā)送的數(shù)據(jù)量,以避免數(shù)據(jù)的擁塞和丟失。 -
擁塞控制:TCP使用擁塞控制機(jī)制來避免網(wǎng)絡(luò)擁塞。發(fā)送方根據(jù)網(wǎng)絡(luò)狀況動態(tài)調(diào)整發(fā)送速率,以避免發(fā)送過多的數(shù)據(jù)導(dǎo)致網(wǎng)絡(luò)擁塞。TCP使用擁塞窗口 (congestion window)來控制發(fā)送方的發(fā)送速率。擁塞窗口的大小可以根據(jù)網(wǎng)絡(luò)狀況動態(tài)調(diào)整,以確保網(wǎng)絡(luò)的穩(wěn)定性和可靠性。 -
最大消息長度:為了防止因數(shù)據(jù)包過大而導(dǎo)致傳輸錯(cuò)誤,TCP設(shè)定了最大消息長度的限制
注意:TCP 可靠傳輸保證的是傳輸層語義,不保證應(yīng)用一定成功處理。比如 服務(wù)端 read() 到了完整數(shù)據(jù),TCP 任務(wù)就算完成了。至于業(yè)務(wù)代碼后面是回滾了、報(bào)空指針了、還是數(shù)據(jù)寫庫失敗了,那已經(jīng)不是 TCP 的職責(zé)了
簡單總結(jié): 序列號負(fù)責(zé)編號和排序,ACK負(fù)責(zé)確認(rèn),超時(shí)重傳負(fù)責(zé)補(bǔ)發(fā),快速重傳負(fù)責(zé)提前發(fā)現(xiàn)丟包,去重負(fù)責(zé)避免重復(fù)數(shù)據(jù),滑動窗口負(fù)責(zé)流量協(xié)調(diào), 校驗(yàn)和負(fù)責(zé)基本的數(shù)據(jù)完整性校驗(yàn)。
1.2 三次握手
1.2.1 三次握手定義
客戶端向服務(wù)器發(fā)送建立連接請求

一開始,客戶端和服務(wù)端都處于 CLOSE 狀態(tài)。先是服務(wù)端主動監(jiān)聽某個(gè)端口,處于 LISTEN 狀態(tài)
- 第一次握手:主機(jī) A 發(fā)送位碼為
syn=1,隨機(jī)產(chǎn)生seq number=1234567的數(shù)據(jù)包到服務(wù)器,主機(jī) B 由SYN=1知道, A 要求建立聯(lián)機(jī);該報(bào)文不包含應(yīng)用層數(shù)據(jù),之后客戶端處于SYN-SENT狀態(tài)。
ffdd46ddbb5753f3b94af12bc50449d7_0f1eaff0c5f14b198f33cc80717c9028.png
- 第二次握手:主 機(jī) B 收 到 請 求 后 要 確 認(rèn) 聯(lián) 機(jī) 信 息 , 向 A 發(fā) 送
ack number=( 主 機(jī) A 的seq+1),SYN=1,ACK=1,隨機(jī)產(chǎn)生seq=7654321的包,把TCP首部的確認(rèn)應(yīng)答號,把SYN和ACK標(biāo)志位置為 1,最后把該報(bào)文發(fā)給客戶端,該報(bào)文也不包含應(yīng)用層數(shù)據(jù),之后服務(wù)端處于SYN-RCVD狀態(tài)。
image.png
- 第三次握手: 主機(jī) A 收到后檢查
ack number是否正確,即第一次發(fā)送的seq number+1,以及位碼ACK是否為 1,若正確, 主機(jī) A 會再發(fā)送ack number=(主機(jī) B 的 seq+1),ACK=1,主機(jī) B 收到后確認(rèn)seq 值與ACK=1則連接建立成功。最后把報(bào)文發(fā)送給服務(wù)端,這次報(bào)文可以攜帶客戶到服務(wù)端的數(shù)據(jù),之后客戶端處于ESTABLISHED狀態(tài)。
2ccb2e27d5b591016e3517a698d7586c_63ede66387b84a9aa04b93b37bd9df92.png
最后,服務(wù)端收到客戶端的應(yīng)答報(bào)文后,也進(jìn)入 ESTABLISHED 狀態(tài)
1.2.2 三次握手問題
1.2.2.1 問題引入分析
概括起來,是這兩個(gè)問題:
-
問:TCP三次握手中,客戶端收到的第二次握手中ack確認(rèn)號不是自己期望的,會發(fā)生什么?是直接丟棄 or 回RST報(bào)文?
答:回RST報(bào)文 -
問:什么情況下會收到不正確的 ack(第二次握手中的 ack) 呢
答:當(dāng)客戶端發(fā)起多次SYN報(bào)文,然后網(wǎng)絡(luò)擁堵的情況下,舊的 SYN 報(bào)文比新的 SYN 報(bào)文早抵達(dá)服務(wù)端,此時(shí)服務(wù)端就會按照收到的舊的 SYN 報(bào)文回復(fù)syn+ack報(bào)文,而此報(bào)文的確認(rèn)號并不是客戶端期望收到的,于是客戶端就會回RST報(bào)文
假如 TCP三次握手中,客戶端收到的第二次握手中 ack 確認(rèn)號不是自己期望的過程如下:

當(dāng)客戶端連續(xù)發(fā)送多次建立連接的 SYN 報(bào)文,然后在網(wǎng)絡(luò)擁堵的情況,就會發(fā)生客戶端收到不正確的 ack 的情況。具體過程如下:
- 客戶端先發(fā)送了
SYN(seq = 90)報(bào)文,但是被網(wǎng)絡(luò)阻塞了,服務(wù)端并沒有收到,接著客戶端又重新發(fā)送了SYN(seq = 100)報(bào)文,注意不是重傳SYN,重傳的SYN的序列號是一樣的。 -
舊 SYN 報(bào)文比最新的 SYN報(bào)文早到達(dá)了服務(wù)端,那么此時(shí)服務(wù)端就會回一個(gè)SYN + ACK報(bào)文給客戶端,此報(bào)文的確認(rèn)號是 91(90+1)。 - 客戶端收到后,發(fā)行自己期望收到的確認(rèn)號應(yīng)該是 100+1,而不是 90 + 1,于是就會回
RST報(bào)文。 - 服務(wù)端收到 RST 報(bào)文后,就會中止連接。
- 后續(xù)最新的 SYN 抵達(dá)了服務(wù)端后,客戶端與服務(wù)端就可以正常的完成三次握手了。
上述中的舊 SYN 報(bào)文稱為歷史連接,TCP 使用三次握手建立連接的最主要原因就是防止歷史連接初始化了連接。
1.2.2.2 歷史連接
如果是兩次握手連接,就無法阻止歷史連接,那為什么TCP 兩次握手為什么無法阻止歷史連接呢?
先說結(jié)論,主要是因?yàn)樵趦纱挝帐值那闆r下,被動發(fā)起方沒有中間狀態(tài)給主動發(fā)起方來阻止歷史連接,導(dǎo)致被動發(fā)起方可能建立一個(gè)歷史連接,造成資源浪費(fèi)。
假如在兩次握手的情況下,被動發(fā)起方在收到 SYN 報(bào)文后,就進(jìn)入 ESTABLISHED 狀態(tài),意味著這時(shí)可以給對方發(fā)送數(shù)據(jù)給,但是主動發(fā)起方此時(shí)還沒有進(jìn)入 ESTABLISHED 狀態(tài),假設(shè)這次是歷史連接,主動發(fā)起方判斷到此次連接為歷史連接,那么就會回 RST 報(bào)文來斷開連接,而被動發(fā)起方在第一次握手的時(shí)候就進(jìn)入 ESTABLISHED 狀態(tài),所以它可以發(fā)送數(shù)據(jù)的,但是它并不知道這個(gè)是歷史連接,它只有在收到 RST報(bào)文后,才會斷開連接。

可以看到,上面這種場景下,被動發(fā)起方在向主動發(fā)起方發(fā)送數(shù)據(jù)前,并沒有阻止掉歷史連接,導(dǎo)致被動發(fā)起方建立了一個(gè)歷史連接,又白白發(fā)送了數(shù)據(jù),妥妥地浪費(fèi)了被動發(fā)起方的資源。
因此,要解決這種現(xiàn)象,最好就是在被動發(fā)起方發(fā)送數(shù)據(jù)前,也就是建立連接之前,要阻止掉歷史連接,這樣就不會造成資源浪費(fèi),而要實(shí)現(xiàn)這個(gè)功能,就需要三次握手。
1.2.2.3 同步雙方初始序列號
TCP 協(xié)議的通信雙方, 都必須維護(hù)一個(gè)序列號, 序列號是可靠傳輸?shù)囊粋€(gè)關(guān)鍵因素,它的作用:
- 接收方可以去除重復(fù)的數(shù)據(jù);
- 接收方可以根據(jù)數(shù)據(jù)包的序列號按序接收;
- 可以標(biāo)識發(fā)送出去的數(shù)據(jù)包中, 哪些是已經(jīng)被對方收到的(通過
ACK報(bào)文中的序列號知道);
可見,序列號在 TCP 連接中占據(jù)著非常重要的作用,所以當(dāng)客戶端發(fā)送攜帶初始序列號的 SYN 報(bào)文的時(shí)候,需要服務(wù)端回一個(gè) ACK 應(yīng)答報(bào)文,表示客戶端的 SYN 報(bào)文已被服務(wù)端成功接收,那當(dāng)服務(wù)端發(fā)送初始序列號給客戶端的時(shí)候,依然也要得到客戶端的應(yīng)答回應(yīng),這樣一來一回,才能確保雙方的初始序列號能被可靠的同步。

四次握手其實(shí)也能夠可靠的同步雙方的初始化序號,但由于第二步和第三步可以優(yōu)化成一步,所以就成了 三次握手
而兩次握手只保證了一方的初始序列號能被對方成功接收,沒辦法保證雙方的初始序列號都能被確認(rèn)接收。
1.2.2.4 避免資源浪費(fèi)
如果只有兩次握手,當(dāng)客戶端發(fā)生的 SYN 報(bào)文在網(wǎng)絡(luò)中阻塞,客戶端沒有接收到 ACK 報(bào)文,就會重新發(fā)送 SYN ,由于沒有第三次握手,服務(wù)端不清楚客戶端是否收到了自己回復(fù)的 ACK 報(bào)文,所以服務(wù)端每收到一個(gè) SYN 就只能先主動建立一個(gè)連接,這會造成什么情況呢?
如果客戶端發(fā)送的
SYN報(bào)文在網(wǎng)絡(luò)中阻塞了,重復(fù)發(fā)送多次SYN報(bào)文,那么服務(wù)端在收到請求后就會建立多個(gè)冗余的無效鏈接,造成不必要的資源浪費(fèi)。
8976a591396d25d5e33c4d78d499436c_253cab9a17b94525affed6b485c98bcf.png
兩次握手會造成資源浪費(fèi)
即兩次握手會造成消息滯留情況下,服務(wù)端重復(fù)接受無用的連接請求 SYN 報(bào)文,而造成重復(fù)分配資源。
1.3 四次揮手
TCP 建立連接要進(jìn)行三次握手,而斷開連接要進(jìn)行四次。這是由于 TCP 的半關(guān)閉造成的。因?yàn)?TCP 連接是全雙工的(即數(shù)據(jù)可在兩個(gè)方向上同時(shí)傳遞)所以進(jìn)行關(guān)閉時(shí)每個(gè)方向上都要單獨(dú)進(jìn)行關(guān)閉。這個(gè)單方向的關(guān)閉就叫半關(guān)閉。當(dāng)一方完成它的數(shù)據(jù)發(fā)送任務(wù),就發(fā)送一個(gè) FIN 來向另一方通告將要終止這個(gè)方向的連接
首先進(jìn)行關(guān)閉的一方將執(zhí)行主動關(guān)閉,而另一方執(zhí)行被動關(guān)閉

- 關(guān)閉客戶端到服務(wù)器的連接:首先客戶端 A 發(fā)送一個(gè)
FIN,用來關(guān)閉客戶到服務(wù)器的數(shù)據(jù)傳送,然后等待服務(wù)器的確認(rèn)。其中終止標(biāo)志位FIN=1,序列號seq=u - 服務(wù)器收到這個(gè)
FIN,它發(fā)回一個(gè)ACK,確認(rèn)號ack為收到的序號加 1 - 關(guān)閉服務(wù)器到客戶端的連接:也是發(fā)送一個(gè)
FIN給客戶端。 - 客戶段收到
FIN后,并發(fā)回一個(gè)ACK報(bào)文確認(rèn),并將確認(rèn)序號 seq設(shè)置為收到序號加 1
主機(jī) A 發(fā)送 FIN 后,進(jìn)入終止等待狀態(tài), 服務(wù)器 B 收到主機(jī) A 連接釋放報(bào)文段后,就立即給主機(jī) A 發(fā)送確認(rèn),然后服務(wù)器 B 就進(jìn)入 close-wait 狀態(tài),此時(shí) TCP 服務(wù)器進(jìn)程就通知高層應(yīng)用進(jìn)程,因而從 A 到 B 的連接就釋放了。此時(shí)是半關(guān)閉狀態(tài)。即 A 不可以發(fā)送給B,但是 B 可以發(fā)送給 A。此時(shí),若 B 沒有數(shù)據(jù)報(bào)要發(fā)送給 A 了,其應(yīng)用進(jìn)程就通知 TCP 釋放連接,然后發(fā)送給 A 連接釋放報(bào)文段,并等待確認(rèn)。 A 發(fā)送確認(rèn)后,進(jìn)入 time-wait
注意,此時(shí) TCP 連接還沒有釋放掉,然后經(jīng)過時(shí)間等待計(jì)時(shí)器設(shè)置的 2MSL 后, A 才進(jìn)入到close狀態(tài)
在四次揮手期間,服務(wù)端不接收報(bào)文而發(fā)送RST報(bào)文給客戶端,客戶端收到RST報(bào)文會報(bào)錯(cuò)(NoHttpResponseException)



