TCP的三次握手和四次揮手

網(wǎng)絡(luò)層可以實(shí)現(xiàn)兩個(gè)主機(jī)之間的通信,但是并不具體,因?yàn)椋嬲M(jìn)行通信的實(shí)體是在主機(jī)中的進(jìn)程,是一個(gè)主機(jī)中的一個(gè)進(jìn)程與另外一個(gè)主機(jī)中的一個(gè)進(jìn)程再交換數(shù)據(jù)。IP協(xié)議雖然能把數(shù)據(jù)報(bào)文送到目的主機(jī),但是并沒(méi)有交付給主機(jī)的具體應(yīng)用進(jìn)程。而端到端的通信才應(yīng)該是應(yīng)用進(jìn)程之間的通信。

  1. UDP 在傳送數(shù)據(jù)前不需要先建立連接,遠(yuǎn)地的主機(jī)在收到UDP報(bào)文后也不需要給出任何確認(rèn)。雖然UDP不提供可靠交付,但是正是因?yàn)檫@樣,省去和很多的開(kāi)銷(xiāo),使得它的速度比較快,比如一些對(duì)實(shí)時(shí)性要求較高的服務(wù),就常常使用的是UDP。對(duì)應(yīng)的應(yīng)用層的協(xié)議主要有 DNS,TFTP,DHCP,SNMP,NFS 等。
    2.TCP 提供面向連接的服務(wù),在傳送數(shù)據(jù)之前必須先建立連接,數(shù)據(jù)傳送完成之后要釋放連接。TCP是一種可靠的運(yùn)輸服務(wù),但是正因?yàn)檫@樣,不可避免的增加了許多的開(kāi)銷(xiāo),比如確認(rèn),流量控制等。對(duì)應(yīng)的應(yīng)用層的協(xié)議主要有 SMTP,TELNET,HTTP,FTP 等。

常用的端口號(hào)

應(yīng)用程序 FTP TFTP TELNET SMTP DNS HTTP SSH MYSQL
熟知端口 21,20 69 23 25 53 80 22 3306
傳輸層協(xié)議 TCP UDP TCP TCP UDP TCP TCP TCP

TCP概述

TCP把連接作為最基本的對(duì)象,每一條TCP連接都有兩個(gè)端點(diǎn),這種端點(diǎn)我們叫作套接字(socket),它的定義為端口號(hào)拼接到IP地址即構(gòu)成了套接字,例如,若IP地址為192.3.4.16 而端口號(hào)為80,那么得到的套接字為192.3.4.16:80。

TCP報(bào)文首部

image.png

從上圖中我們可以看出:

  1. 整個(gè)首部固定占20個(gè)字節(jié)
  2. 源端口和目的端口,各占2個(gè)字節(jié),分別為入源端口和目的端口
  3. 序號(hào),占4個(gè)字節(jié),TCP連接中傳送的字節(jié)流中的每個(gè)字節(jié)都按順序編號(hào)。例如,一段報(bào)文的序號(hào)字段值是301,而攜帶的數(shù)據(jù)共有100字段,顯然下一個(gè)報(bào)文段(如果還有的話(huà))的數(shù)據(jù)序號(hào)應(yīng)該從401開(kāi)始;
  4. 確認(rèn)號(hào),占4個(gè)字節(jié),是期望收到對(duì)方下一個(gè)報(bào)文的第一個(gè)數(shù)據(jù)字節(jié)的序號(hào)。例如,B收到了A發(fā)送過(guò)來(lái)的報(bào)文,其序列號(hào)字段是501,而數(shù)據(jù)長(zhǎng)度是200字節(jié),這表明B正確的收到了A發(fā)送的到序號(hào)700為止的數(shù)據(jù)。因此,B期望收到A的下一個(gè)數(shù)據(jù)序號(hào)是701,于是B在發(fā)送給A的確認(rèn)報(bào)文段中把確認(rèn)號(hào)置為701
  5. 數(shù)據(jù)偏移,占4位,它指出TCP報(bào)文的數(shù)據(jù)距離TCP報(bào)文段的起始處有多遠(yuǎn);
  6. 保留,占6位,保留今后使用,但目前應(yīng)都為0
  7. 緊急URG,當(dāng)URG=1,表明緊急指針字段有效。告訴系統(tǒng)此報(bào)文段中有緊急數(shù)據(jù);
  8. 確認(rèn)ACK,僅當(dāng)ACK=1時(shí),確認(rèn)號(hào)字段才有效。TCP規(guī)定,在連接建立后所有報(bào)文的傳輸都必須把ACK置1;
  9. 推送PSH,當(dāng)兩個(gè)應(yīng)用進(jìn)程進(jìn)行交互式通信時(shí),有時(shí)在一端的應(yīng)用進(jìn)程希望在鍵入一個(gè)命令后立即就能收到對(duì)方的響應(yīng),這時(shí)候就將PSH=1;
  10. 復(fù)位RST,當(dāng)RST=1,表明TCP連接中出現(xiàn)嚴(yán)重差錯(cuò),必須釋放連接,然后再重新建立連接;
  11. 同步SYN,在連接建立時(shí)用來(lái)同步序號(hào)。當(dāng)SYN=1,ACK=0,表明是連接請(qǐng)求報(bào)文,若同意連接,則響應(yīng)報(bào)文中應(yīng)該使SYN=1,ACK=1
  12. 終止FIN,用來(lái)釋放連接。當(dāng)FIN=1,表明此報(bào)文的發(fā)送方的數(shù)據(jù)已經(jīng)發(fā)送完畢,并且要求釋放;
  13. 窗口,占2字節(jié),指的是通知接收方,發(fā)送本報(bào)文你需要有多大的空間來(lái)接受;
  14. 檢驗(yàn)和,占2字節(jié),校驗(yàn)首部和數(shù)據(jù)這兩部分;
  15. 緊急指針,占2字節(jié),指出本報(bào)文段中的緊急數(shù)據(jù)的字節(jié)數(shù);
  16. 選項(xiàng),長(zhǎng)度可變,定義一些其他的可選的參數(shù)。

TCP鏈接的建立(三次握手)

  • 三次握手過(guò)程圖解:


    image.png

最開(kāi)始的時(shí)候客戶(hù)端和服務(wù)器都處于CLOSED狀態(tài),主動(dòng)打開(kāi)鏈接的為客戶(hù)端,被動(dòng)打開(kāi)鏈接的是服務(wù)器。

  1. TCP服務(wù)器進(jìn)程先創(chuàng)建傳輸控制塊TCB,時(shí)刻準(zhǔn)備接受客戶(hù)進(jìn)程的鏈接請(qǐng)求,此時(shí)服務(wù)器就進(jìn)入了LISTEN(監(jiān)聽(tīng))狀態(tài),TCP客戶(hù)進(jìn)程也是先創(chuàng)建傳輸控制塊TCB。
  2. 第一次握手:客戶(hù)段向服務(wù)器發(fā)出建立鏈接請(qǐng)求報(bào)文時(shí),這時(shí)請(qǐng)求報(bào)文首部中的同部位SYN=1,同時(shí)隨機(jī)選擇一個(gè)初始序列號(hào)seq=x,此時(shí),TCP客戶(hù)端進(jìn)程進(jìn)入了SYN-SENT(同步已發(fā)送狀態(tài))狀態(tài)。TCP規(guī)定,SYN報(bào)文段(SYN=1的報(bào)文段)不能攜帶數(shù)據(jù),但是需要消耗掉一個(gè)序號(hào)
  3. 第二次握手:服務(wù)器收到請(qǐng)求報(bào)文后,如果同意鏈接,則發(fā)出確認(rèn)報(bào)文。確認(rèn)報(bào)文中應(yīng)該ACK = 1 & SYN = 1, 確認(rèn)號(hào)ack=x+1,同時(shí)也要為自己初始化一個(gè)序列號(hào)seq=y,此時(shí)TCP服務(wù)器進(jìn)程進(jìn)入了SYN-RCVD(同步收到)狀態(tài)。這個(gè)報(bào)文也不能攜帶數(shù)據(jù),但是同樣要消耗掉一個(gè)序號(hào)
  4. 第三次握手:TCP客戶(hù)端收到服務(wù)器的確認(rèn)后,還需要向服務(wù)器給出確認(rèn)。確認(rèn)報(bào)文的ACK=1, ack = y + 1,自己的序列號(hào)seq = x + 1, 此時(shí),TCP鏈接建立,客戶(hù)端進(jìn)入ESTABLISHED(已建立連接)狀態(tài)。TCP規(guī)定ACK報(bào)文段可以攜帶數(shù)據(jù),但是如果不攜帶數(shù)據(jù)則不消耗序號(hào)。
  5. 當(dāng)服務(wù)器收到客戶(hù)端的確認(rèn)后也進(jìn)入ESTABLISHED(TCP已建立連接)狀態(tài),完成三次握手,此后雙發(fā)就可以開(kāi)始通信了。

三次握手的主要目的是保證連接是雙工的,可靠更多的是通過(guò)重傳機(jī)制來(lái)保證的。

TCP連接的釋放(四次揮手)

四次揮手圖解:


image.png

數(shù)據(jù)傳輸完畢后,雙方都可以釋放連接。最開(kāi)始的使用,客戶(hù)端和服務(wù)器都是出于ESTABLISHED狀態(tài),然后客戶(hù)端主動(dòng)關(guān)閉,服務(wù)器被動(dòng)關(guān)閉。

  1. 第一次揮手:客戶(hù)端發(fā)出鏈接釋放報(bào)文,并且停止發(fā)送數(shù)據(jù)。釋放數(shù)據(jù)報(bào)文首部,F(xiàn)IN = 1,其序列號(hào)seq=u(等于前面已經(jīng)傳送過(guò)來(lái)的數(shù)據(jù)的最后一個(gè)字節(jié)的序號(hào)+ 1),此時(shí),客戶(hù)端進(jìn)入FIN-WAIT-1(終止等待1)狀態(tài)。TCP規(guī)定,F(xiàn)IN報(bào)文段即使不攜帶數(shù)據(jù),也要消耗一個(gè)序號(hào)
  2. 第二次揮手:服務(wù)器收到鏈接釋放報(bào)文,發(fā)出確認(rèn)報(bào)文,ACK = 1 & ack = u + 1,并且?guī)献止?jié)的序列號(hào)seq = v,此時(shí),服務(wù)端進(jìn)入了CLOSE-WAIT(關(guān)閉等待)狀態(tài)。TCP服務(wù)器通知高層的應(yīng)用進(jìn)程,客戶(hù)端向服務(wù)器的方向就釋放了,這時(shí)候處于半關(guān)閉狀態(tài),即客戶(hù)端已經(jīng)沒(méi)有數(shù)據(jù)要發(fā)送了,但是服務(wù)器若發(fā)送數(shù)據(jù),客戶(hù)端依然要接收。這個(gè)狀態(tài)還要持續(xù)一段時(shí)間,也就是整個(gè)CLOSE-WAIT狀態(tài)持續(xù)的時(shí)間。
  3. 客戶(hù)端收到服務(wù)器的確認(rèn)請(qǐng)求后,此時(shí),客戶(hù)端就進(jìn)入FIN-WAIT-2(終止等待2)狀態(tài),等待服務(wù)器發(fā)送鏈接釋放報(bào)文(在這之前還需要接收服務(wù)器發(fā)送的最后的數(shù)據(jù))
  4. 第三次揮手:服務(wù)器將最后的數(shù)據(jù)發(fā)送完畢后,就像客戶(hù)端發(fā)送鏈接釋放報(bào)文,F(xiàn)IN=1 & ack = u + 1,由于在半關(guān)閉狀態(tài),服務(wù)器很可能又發(fā)送了一些數(shù)據(jù),假設(shè)此時(shí)的序列號(hào)為seq=w, 此時(shí),服務(wù)器就進(jìn)入了LAST-ACK(最后確認(rèn))狀態(tài),等待客戶(hù)端的確認(rèn)
  5. 第四次揮手:客戶(hù)端收到服務(wù)器的鏈接釋放報(bào)文后,必須發(fā)出確認(rèn),ACK = 1 & ack = w + 1, 而自己的序列號(hào)是seq = u + 1,客戶(hù)端就進(jìn)入了TIME-WAIT(時(shí)間等待)狀態(tài)。注意此時(shí)TCP鏈接還沒(méi)有釋放,必須經(jīng)過(guò)2*MSL(最長(zhǎng)報(bào)文段壽命)的時(shí)間后,當(dāng)客戶(hù)端撤銷(xiāo)相應(yīng)的TCB后,才進(jìn)入CLOSED狀態(tài)
  6. 服務(wù)器只要收到了客戶(hù)端發(fā)出的確認(rèn),立即進(jìn)入CLOSED狀態(tài)。同樣,撤銷(xiāo)TCB后,就結(jié)束了這次的TCP鏈接。可以看到,服務(wù)器結(jié)束TCP鏈接的時(shí)間要比客戶(hù)端早一些。

為什么TCP客戶(hù)端最后還要發(fā)送一次確認(rèn)呢?

答:為了防止已經(jīng)失效的鏈接請(qǐng)求報(bào)文突然又傳送到了服務(wù)器,從而產(chǎn)生錯(cuò)誤。

如果使用的是兩次握手建立連接,假設(shè)有這樣一種場(chǎng)景:客戶(hù)端發(fā)送了第一個(gè)請(qǐng)求連接并且沒(méi)有丟失,只是因?yàn)樵诰W(wǎng)絡(luò)節(jié)點(diǎn)中滯留的時(shí)間太長(zhǎng)了,由于TCP的客戶(hù)端遲遲沒(méi)有收到確認(rèn)報(bào)文,以為服務(wù)器沒(méi)有收到,此時(shí)重新向服務(wù)器發(fā)送這條報(bào)文,此后客戶(hù)端和服務(wù)器經(jīng)過(guò)兩次握手完成連接,傳輸數(shù)據(jù),然后關(guān)閉連接。此時(shí),此前滯留的第一次請(qǐng)求連接,網(wǎng)絡(luò)通暢了到達(dá)了服務(wù)器,這個(gè)報(bào)文本該是失效的,但是兩次握手的機(jī)制將會(huì)讓客戶(hù)端和服務(wù)器再次建立連接,這將導(dǎo)致不必要的錯(cuò)誤和資源的浪費(fèi)。如果采用的是3次握手,就算是那一次失效的報(bào)文傳送過(guò)來(lái)了,服務(wù)端接收到了那條失效報(bào)文并且回復(fù)了確認(rèn)報(bào)文,但是客戶(hù)端不會(huì)再次發(fā)出確認(rèn),由于服務(wù)器收不到確認(rèn),就知道客戶(hù)端并沒(méi)有請(qǐng)求連接。

為什么不能用兩次握手進(jìn)行連接?

答:我們知道,3次握手完成兩個(gè)重要的功能,既要雙方做好發(fā)送數(shù)據(jù)的準(zhǔn)備工作(雙方都知道彼此已準(zhǔn)備好),也要允許雙方就初始序列號(hào)進(jìn)行協(xié)商,這個(gè)序列號(hào)在握手過(guò)程中被發(fā)送和確認(rèn)。
現(xiàn)在把三次握手改成僅需要兩次握手,死鎖是可能發(fā)生的。作為例子,考慮計(jì)算機(jī)S和C之間的通信,假定C給S發(fā)送一個(gè)連接請(qǐng)求分組,S收到了這個(gè)分組,并發(fā) 送了確認(rèn)應(yīng)答分組。按照兩次握手的協(xié)定,S認(rèn)為連接已經(jīng)成功地建立了,可以開(kāi)始發(fā)送數(shù)據(jù)分組。可是,C在S的應(yīng)答分組在傳輸中被丟失的情況下,將不知道S 是否已準(zhǔn)備好,不知道S建立什么樣的序列號(hào),C甚至懷疑S是否收到自己的連接請(qǐng)求分組。在這種情況下,C認(rèn)為連接還未建立成功,將忽略S發(fā)來(lái)的任何數(shù)據(jù)分 組,只等待連接確認(rèn)應(yīng)答分組。而S在發(fā)出的分組超時(shí)后,重復(fù)發(fā)送同樣的分組。這樣就形成了死鎖。

校評(píng):這個(gè)解釋也值得商榷,這里指說(shuō)S超時(shí)重傳,難道C沒(méi)有收到S的ACK信號(hào),不會(huì)重新發(fā)送SYN信號(hào)么? 只要重新發(fā)送SYN,S端自然也會(huì)發(fā)送確認(rèn)應(yīng)答分組,這樣就不會(huì)導(dǎo)致死鎖。

如果已經(jīng)建立了連接,但是客戶(hù)端突然出現(xiàn)故障了怎么辦?

答:TCP還有一個(gè)保活計(jì)時(shí)器,顯然,客戶(hù)端如果出現(xiàn)故障,服務(wù)器不能一直等下去,白白浪費(fèi)資源,服務(wù)器每收到一次客戶(hù)端的請(qǐng)求后都會(huì)重新復(fù)位這個(gè)計(jì)時(shí)器,通常是設(shè)置為2小時(shí),如果兩個(gè)小時(shí)還沒(méi)有收到客戶(hù)端的任何數(shù)據(jù),服務(wù)器就會(huì)發(fā)送一個(gè)探測(cè)報(bào)文段,以后每隔75秒發(fā)送一次,如果一連發(fā)送10個(gè)探測(cè)報(bào)文仍然沒(méi)有反應(yīng),服務(wù)器就認(rèn)為客戶(hù)端出現(xiàn)了故障,接著就關(guān)閉連接。

為什么連接的時(shí)候是三次握手,關(guān)閉的時(shí)候卻是四次揮手?

答:因服務(wù)端收到客戶(hù)端的SYN連接請(qǐng)求報(bào)文后,可以直接發(fā)送SYN+ACK報(bào)文。其中ACK報(bào)文是用來(lái)應(yīng)答的,SYN報(bào)文是用來(lái)同步的。但是關(guān)閉連接時(shí),當(dāng)服務(wù)端收到FIN報(bào)文時(shí),很可能并不會(huì)立即關(guān)閉Socket,僅僅表示對(duì)方不再發(fā)送數(shù)據(jù)了,但是還能接收數(shù)據(jù),而自己也未必全部數(shù)據(jù)都發(fā)送完畢,所以只能先回復(fù)一個(gè)ACK報(bào)文,告訴客戶(hù)端“你發(fā)的FIN報(bào)文我收到了”,只有等到我服務(wù)端所有的報(bào)文都發(fā)送完了,我才能發(fā)送FIN報(bào)文,因此不能一起發(fā)送。故需要四次揮手。

為什么四次揮手中客戶(hù)端還需要等待2MSL?

答:MSL(Maximum Segment Lifetime),TCP允許不同的實(shí)現(xiàn)可以設(shè)置不同的MSL值。
第一,保證客戶(hù)端發(fā)送的最后一個(gè)ACK報(bào)文能夠到達(dá)服務(wù)器,因?yàn)檫@個(gè)ACK報(bào)文可能丟失,站在服務(wù)器的角度看來(lái),我已經(jīng)發(fā)送了FIN+ACK報(bào)文請(qǐng)求斷開(kāi)了,客戶(hù)端還沒(méi)有給我回應(yīng),應(yīng)該是我發(fā)送的請(qǐng)求斷開(kāi)報(bào)文它沒(méi)有收到,于是服務(wù)器又會(huì)重新發(fā)送一次,而客戶(hù)端就能在這個(gè)2MSL時(shí)間段內(nèi)收到這個(gè)重傳的報(bào)文,接著給出回應(yīng)報(bào)文,并且會(huì)重啟2MSL計(jì)時(shí)器。
第二,防止類(lèi)似與“三次握手”中提到了的“已經(jīng)失效的連接請(qǐng)求報(bào)文段”出現(xiàn)在本連接中。客戶(hù)端發(fā)送完最后一個(gè)確認(rèn)報(bào)文后,在這個(gè)2MSL時(shí)間中,就可以使本連接持續(xù)的時(shí)間內(nèi)所產(chǎn)生的所有報(bào)文段都從網(wǎng)絡(luò)中消失。這樣新的連接中不會(huì)出現(xiàn)舊連接的請(qǐng)求報(bào)文。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容