三次握手建立連接
- 客戶主機(jī)發(fā)送請(qǐng)求報(bào)文,F(xiàn)lag設(shè)置為 SYN,帶上 Seq, 假設(shè)為 clientNo;
- 服務(wù)主機(jī)接收到報(bào)文后,為這次連接分配資源,并回復(fù)報(bào)文, Flag設(shè)置為 [SYN, ACK], 帶上 Seq, 假設(shè)為 serverNo,同時(shí)帶上 Ack,為clientNo + 1;
- 客戶主機(jī)收到報(bào)文后,為鏈接分配資源,也會(huì)發(fā)送回復(fù)報(bào)文,F(xiàn)lag設(shè)置為 ACK, 帶上 Seq,為 clientNo + 1, 并帶上 Ack,為 serverNo + 1。
三次握手后,TCP連接正式建立。具體流程如下圖所示:

四次揮手?jǐn)嚅_(kāi)連接
- 客戶主機(jī)發(fā)送斷開(kāi)連接請(qǐng)求(也可以是服務(wù)主機(jī)首先發(fā)送該請(qǐng)求,如 Http 服務(wù)器),發(fā)送報(bào)文,F(xiàn)lag設(shè)置為 FIN,并帶上 Seq,假設(shè)為 clientNo。發(fā)送該報(bào)文,可以通俗的理解為:客戶主機(jī)告訴服務(wù)主機(jī),我們沒(méi)啥好說(shuō)的了,你那邊沒(méi)什么異議的話,要不我們分手吧。
- 服務(wù)主機(jī)收到 Fin 報(bào)文后,發(fā)送回復(fù)報(bào)文,F(xiàn)lags設(shè)置為 ACK,帶上Seq,假設(shè)為 serverNo1,同時(shí)帶上 Ack,為clientNo + 1??梢酝ㄋ椎睦斫鉃椋何叶愕囊馑剂?,讓我先準(zhǔn)備準(zhǔn)備先。此時(shí),提出分手的主機(jī)進(jìn)入 FIN_WAIT 狀態(tài),等待服務(wù)主機(jī)的分手報(bào)文。
- 服務(wù)主機(jī)確定數(shù)據(jù)已經(jīng)發(fā)送完成,則向客戶主機(jī)發(fā)送斷開(kāi)報(bào)文,F(xiàn)lag設(shè)置為 FIN,并帶上 Seq,假設(shè)為 serverNo2??梢岳斫鉃椋罕坛?,我這邊事情完結(jié)了,我們可以分手了。
- 客戶主機(jī)收到 FIN 報(bào)文后,知道可以關(guān)閉網(wǎng)絡(luò),發(fā)送回復(fù)報(bào)文,設(shè)置Flags為 ACK,帶上Seq為clientNo2,Ack為ServerNo2 + 1,之后進(jìn)入 TIME_WAIT狀態(tài),如果 2MSL 后,服務(wù)主機(jī)沒(méi)有回應(yīng),說(shuō)明服務(wù)主機(jī)已經(jīng)正常關(guān)閉,客戶主機(jī)也關(guān)閉連接。
具體流程如下圖所示:

抓包實(shí)例
下圖是用 WireShark 對(duì) HTTP 請(qǐng)求的抓包實(shí)例:

前三個(gè)包是三次握手,后四個(gè)包是四次揮手
三次握手
- 客戶端發(fā)送 SYN 包,Seq為0
- 服務(wù)端發(fā)送 [SYN, ACK] 包,Seq為0, Ack為1
- 客戶端發(fā)送 ACK 包,Seq為0, Ack為1
四次揮手
- 服務(wù)端發(fā)送 [FIN, ACK] 包,Seq為1226,F(xiàn)lags中的 ACK 不是用于關(guān)閉連接
- 客戶端發(fā)送 ACK 包,Seq為2031, Ack為1227
- 客戶端發(fā)送 [FIN, ACK] 包,Seq為2031
- 服務(wù)端發(fā)送 ACK 包,Seq為1227, Ack=2032
注意
什么要三次握手
在謝希仁的《計(jì)算機(jī)網(wǎng)絡(luò)》中是這樣說(shuō)的:
為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端,因而產(chǎn)生錯(cuò)誤。
在書(shū)中同時(shí)舉了一個(gè)例子,如下:
“已失效的連接請(qǐng)求報(bào)文段”的產(chǎn)生在這樣一種情況下:client發(fā)出的第一個(gè)連接請(qǐng)求報(bào)文段并沒(méi)有丟失,而是在某個(gè)網(wǎng)絡(luò)結(jié)點(diǎn)長(zhǎng)時(shí)間的滯留了,以致延誤到連接釋放以后的某個(gè)時(shí)間才到達(dá)server。本來(lái)這是一個(gè)早已失效的報(bào)文段。但server收到此失效的連接請(qǐng)求報(bào)文段后,就誤認(rèn)為是client再次發(fā)出的一個(gè)新的連接請(qǐng)求。于是就向client發(fā)出確認(rèn)報(bào)文段,同意建立連接。假設(shè)不采用“三次握手”,那么只要server發(fā)出確認(rèn),新的連接就建立了。由于現(xiàn)在client并沒(méi)有發(fā)出建立連接的請(qǐng)求,因此不會(huì)理睬server的確認(rèn),也不會(huì)向server發(fā)送數(shù)據(jù)。但server卻以為新的運(yùn)輸連接已經(jīng)建立,并一直等待client發(fā)來(lái)數(shù)據(jù)。這樣,server的很多資源就白白浪費(fèi)掉了。采用“三次握手”的辦法可以防止上述現(xiàn)象發(fā)生。例如剛才那種情況,client不會(huì)向server的確認(rèn)發(fā)出確認(rèn)。server由于收不到確認(rèn),就知道client并沒(méi)有要求建立連接?!?/p>
這就很明白了,防止了服務(wù)器端的一直等待而浪費(fèi)資源。
什么要四次握手
TCP是全雙工模式,這就意味著:
- 當(dāng)主機(jī)1發(fā)出FIN報(bào)文段時(shí),只是表示主機(jī)1已經(jīng)沒(méi)有數(shù)據(jù)要發(fā)送了,主機(jī)1告訴主機(jī)2,它的數(shù)據(jù)已經(jīng)全部發(fā)送完畢了;但是,這個(gè)時(shí)候主機(jī)1還是可以接受來(lái)自主機(jī)2的數(shù)據(jù);
- 當(dāng)主機(jī)2返回ACK報(bào)文段時(shí),表示它已經(jīng)知道主機(jī)1沒(méi)有數(shù)據(jù)發(fā)送了,但是主機(jī)2還是可以發(fā)送數(shù)據(jù)到主機(jī)1的;
- 當(dāng)主機(jī)2也發(fā)送了FIN報(bào)文段時(shí),這個(gè)時(shí)候就表示主機(jī)2也沒(méi)有數(shù)據(jù)要發(fā)送了,就會(huì)告訴主機(jī)1,我也沒(méi)有數(shù)據(jù)要發(fā)送了,之后彼此就會(huì)愉快的中斷這次TCP連接。