三次握手和四次挥手详细介绍
相對于SOCKET開發(fā)者,TCP創(chuàng)建過程和鏈接折除過程是由TCP/IP協(xié)議棧自動創(chuàng)建的.因此開發(fā)者并不需要控制這個過程.但是對于理解TCP底層運(yùn)作機(jī)制,相當(dāng)有幫助.
而且對于有網(wǎng)絡(luò)協(xié)議工程師之類筆試,幾乎是必考的內(nèi)容.企業(yè)對這個問題熱情之高,出乎我的意料:-)。有時上午面試前強(qiáng)調(diào)這個問題,并重復(fù)講一次,下午幾乎每一個人都被問到這個問題。
因此在這里詳細(xì)解釋一下這兩個過程。
TCP三次握手
所謂三次握手(Three-way Handshake),是指建立一個TCP連接時,需要客戶端和服務(wù)器總共發(fā)送3個包。
三次握手的目的是連接服務(wù)器指定端口,建立TCP連接,并同步連接雙方的序列號和確認(rèn)號并交換 TCP 窗口大小信息.在socket編程中,客戶端執(zhí)行connect()時。將觸發(fā)三次握手。
第一次握手:
客戶端發(fā)送一個TCP的SYN標(biāo)志位置1的包指明客戶打算連接的服務(wù)器的端口,以及初始序號X,保存在包頭的序列號(Sequence Number)字段里。
第二次握手:
服務(wù)器發(fā)回確認(rèn)包(ACK)應(yīng)答。即SYN標(biāo)志位和ACK標(biāo)志位均為1同時,將確認(rèn)序號(Acknowledgement Number)設(shè)置為客戶的I S N加1以.即X+1。
第三次握手.
客戶端再次發(fā)送確認(rèn)包(ACK) SYN標(biāo)志位為0,ACK標(biāo)志位為1.并且把服務(wù)器發(fā)來ACK的序號字段+1,放在確定字段中發(fā)送給對方.并且在數(shù)據(jù)段放寫ISN的+1
SYN攻擊
在三次握手過程中,服務(wù)器發(fā)送SYN-ACK之后,收到客戶端的ACK之前的TCP連接稱為半連接(half-open connect).此時服務(wù)器處于Syn_RECV狀態(tài).當(dāng)收到ACK后,服務(wù)器轉(zhuǎn)入ESTABLISHED狀態(tài).
Syn攻擊就是 攻擊客戶端 在短時間內(nèi)偽造大量不存在的IP地址,向服務(wù)器不斷地發(fā)送syn包,服務(wù)器回復(fù)確認(rèn)包,并等待客戶的確認(rèn),由于源地址是不存在的,服務(wù)器需要不斷的重發(fā)直 至超時,這些偽造的SYN包將長時間占用未連接隊(duì)列,正常的SYN請求被丟棄,目標(biāo)系統(tǒng)運(yùn)行緩慢,嚴(yán)重者引起網(wǎng)絡(luò)堵塞甚至系統(tǒng)癱瘓。
Syn攻擊是一個典型的DDOS攻擊。檢測SYN攻擊非常的方便,當(dāng)你在服務(wù)器上看到大量的半連接狀態(tài)時,特別是源IP地址是隨機(jī)的,基本上可以斷定這是一次SYN攻擊.在Linux下可以如下命令檢測是否被Syn攻擊
netstat -n -p TCP | grep SYN_RECV
一般較新的TCP/IP協(xié)議棧都對這一過程進(jìn)行修正來防范Syn攻擊,修改tcp協(xié)議實(shí)現(xiàn)。主要方法有SynAttackProtect保護(hù)機(jī)制、SYN cookies技術(shù)、增加最大半連接和縮短超時時間等.
但是不能完全防范syn攻擊。
TCP 四次揮手
TCP的連接的拆除需要發(fā)送四個包,因此稱為四次揮手(four-way handshake)。客戶端或服務(wù)器均可主動發(fā)起揮手動作,在socket編程中,任何一方執(zhí)行close()操作即可產(chǎn)生揮手操作。
參見wireshark抓包,實(shí)測的抓包結(jié)果并沒有嚴(yán)格按揮手時序。我估計(jì)是時間間隔太短造成。
注意上面的字段標(biāo)號地段和發(fā)送接收的內(nèi)容序號,可能有個有錯,記不住哪個了,后頭要細(xì)看看
?
第二部分:補(bǔ)充tcp連接過程
?
在TCP/IP協(xié)議中,TCP協(xié)議提供可靠的連接服務(wù),采用三次握手建立一個連接,如圖1所示。
?(1) 第一次握手:建立連接時,客戶端A發(fā)送SYN包(SYN=j)到服務(wù)器B,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器B確認(rèn)。
?(2) 第二次握手:服務(wù)器B收到SYN包,必須確認(rèn)客戶A的SYN(ACK=j+1),同時自己也發(fā)送一個SYN包(SYN=k),即SYN+ACK包,此時服務(wù)器B進(jìn)入SYN_RECV狀態(tài)。
?(3) 第三次握手:客戶端A收到服務(wù)器B的SYN+ACK包,向服務(wù)器B發(fā)送確認(rèn)包ACK(ACK=k+1),此包發(fā)送完畢,客戶端A和服務(wù)器B進(jìn)入ESTABLISHED狀態(tài),完成三次握手。
完成三次握手,客戶端與服務(wù)器開始傳送數(shù)據(jù)。
?
?????????????????????????????? 圖1 TCP三次握手建立連接
由于TCP連接是全雙工的,因此每個方向都必須單獨(dú)進(jìn)行關(guān)閉。這個原則是當(dāng)一方完成它的數(shù)據(jù)發(fā)送任務(wù)后就能發(fā)送一個FIN來終止這個方向的連接。收到一個 FIN只意味著這一方向上沒有數(shù)據(jù)流動,一個TCP連接在收到一個FIN后仍能發(fā)送數(shù)據(jù)。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動關(guān)閉,而另一方執(zhí)行被動關(guān)閉。
(1)客戶端A發(fā)送一個FIN,用來關(guān)閉客戶A到服務(wù)器B的數(shù)據(jù)傳送(報(bào)文段4)。
(2)服務(wù)器B收到這個FIN,它發(fā)回一個ACK,確認(rèn)序號為收到的序號加1(報(bào)文段5)。和SYN一樣,一個FIN將占用一個序號。
(3)服務(wù)器B關(guān)閉與客戶端A的連接,發(fā)送一個FIN給客戶端A(報(bào)文段6)。
(4)客戶端A發(fā)回ACK報(bào)文確認(rèn),并將確認(rèn)序號設(shè)置為收到序號加1(報(bào)文段7)。
TCP采用四次揮手關(guān)閉連接如圖2所示。
?
???????????????????????????????圖2 ?TCP四次揮手關(guān)閉連接
1.為什么建立連接協(xié)議是三次握手,而關(guān)閉連接卻是四次握手呢?
這是因?yàn)榉?wù)端的LISTEN狀態(tài)下的SOCKET當(dāng)收到SYN報(bào)文的連接請求后,它可以把ACK和SYN(ACK起應(yīng)答作用,而SYN起同步作用)放在一個報(bào)文里來發(fā)送。但關(guān)閉連接時,當(dāng)收到對方的FIN報(bào)文通知時,它僅僅表示對方?jīng)]有數(shù)據(jù)發(fā)送給你了;但未必你所有的數(shù)據(jù)都全部發(fā)送給對方了,所以你可能未必會馬上會關(guān)閉SOCKET,也即你可能還需要發(fā)送一些數(shù)據(jù)給對方之后,再發(fā)送FIN報(bào)文給對方來表示你同意現(xiàn)在可以關(guān)閉連接了,所以它這里的ACK報(bào)文和FIN報(bào)文多數(shù)情況下都是分開發(fā)送的。
?
2.為什么TIME_WAIT狀態(tài)還需要等2MSL后才能返回到CLOSED狀態(tài)?
這個問題可以參考《unix 網(wǎng)絡(luò)編程》(第三版,2.7 TIME_WAIT狀態(tài))。
TIME_WAIT狀態(tài)由兩個存在的理由。
(1)可靠的實(shí)現(xiàn)TCP全雙工鏈接的終止。
這是因?yàn)殡m然雙方都同意關(guān)閉連接了,而且握手的4個報(bào)文也都協(xié)調(diào)和發(fā)送完畢,按理可以直接回到CLOSED狀態(tài)(就好比從SYN_SEND狀態(tài)到ESTABLISH狀態(tài)那樣);但是因?yàn)槲覀儽仨氁傧刖W(wǎng)絡(luò)是不可靠的,你無法保證你最后發(fā)送的ACK報(bào)文會一定被對方收到,因此對方處于LAST_ACK狀態(tài)下的SOCKET可能會因?yàn)槌瑫r未收到ACK報(bào)文,而重發(fā)FIN報(bào)文,所以這個TIME_WAIT狀態(tài)的作用就是用來重發(fā)可能丟失的ACK報(bào)文。
?(2)允許老的重復(fù)的分節(jié)在網(wǎng)絡(luò)中消逝。
假 設(shè)在12.106.32.254的1500端口和206.168.1.112.219的21端口之間有一個TCP連接。我們關(guān)閉這個鏈接,過一段時間后在 相同的IP地址和端口建立另一個連接。后一個鏈接成為前一個的化身。因?yàn)樗鼈兊腎P地址和端口號都相同。TCP必須防止來自某一個連接的老的重復(fù)分組在連 接已經(jīng)終止后再現(xiàn),從而被誤解成屬于同一鏈接的某一個某一個新的化身。為做到這一點(diǎn),TCP將不給處于TIME_WAIT狀態(tài)的鏈接發(fā)起新的化身。既然 TIME_WAIT狀態(tài)的持續(xù)時間是MSL的2倍,這就足以讓某個方向上的分組最多存活msl秒即被丟棄,另一個方向上的應(yīng)答最多存活msl秒也被丟棄。 通過實(shí)施這個規(guī)則,我們就能保證每成功建立一個TCP連接時。來自該鏈接先前化身的重復(fù)分組都已經(jīng)在網(wǎng)絡(luò)中消逝了。
?
3. 為什么不能用兩次握手進(jìn)行連接?
我們知道,3次握手完成兩個重要的功能,既要雙方做好發(fā)送數(shù)據(jù)的準(zhǔn)備工作(雙方都知道彼此已準(zhǔn)備好),也要允許雙方就初始序列號進(jìn)行協(xié)商,這個序列號在握手過程中被發(fā)送和確認(rèn)。
??? 現(xiàn)在把三次握手改成僅需要兩次握手,死鎖是可能發(fā)生的。作為例子,考慮計(jì)算機(jī)S和C之間的通信,假定C給S發(fā)送一個連接請求分組,S收到了這個分組,并發(fā) 送了確認(rèn)應(yīng)答分組。按照兩次握手的協(xié)定,S認(rèn)為連接已經(jīng)成功地建立了,可以開始發(fā)送數(shù)據(jù)分組。可是,C在S的應(yīng)答分組在傳輸中被丟失的情況下,將不知道S 是否已準(zhǔn)備好,不知道S建立什么樣的序列號,C甚至懷疑S是否收到自己的連接請求分組。在這種情況下,C認(rèn)為連接還未建立成功,將忽略S發(fā)來的任何數(shù)據(jù)分 組,只等待連接確認(rèn)應(yīng)答分組。而S在發(fā)出的分組超時后,重復(fù)發(fā)送同樣的分組。這樣就形成了死鎖。
?
補(bǔ)充:
a. 默認(rèn)情況下(不改變socket選項(xiàng)),當(dāng)你調(diào)用close( or closesocket,以下說close不再重復(fù))時,如果發(fā)送緩沖中還有數(shù)據(jù),TCP會繼續(xù)把數(shù)據(jù)發(fā)送完。
b. 發(fā)送了FIN只是表示這端不能繼續(xù)發(fā)送數(shù)據(jù)(應(yīng)用層不能再調(diào)用send發(fā)送),但是還可以接收數(shù)據(jù)。
c. 應(yīng)用層如何知道對端關(guān)閉?通常,在最簡單的阻塞模型中,當(dāng)你調(diào)用recv時,如果返回0,則表示對端關(guān)閉。在這個時候通常的做法就是也調(diào)用close,那么TCP層就發(fā)送FIN,繼續(xù)完成四次握手。如果你不調(diào)用close,那么對端就會處于FIN_WAIT_2狀態(tài),而本端則會處于CLOSE_WAIT狀態(tài)。這個可以寫代碼試試。
d. 在很多時候,TCP連接的斷開都會由TCP層自動進(jìn)行,例如你CTRL+C終止你的程序,TCP連接依然會正常關(guān)閉,你可以寫代碼試試。
?
插曲:
?
?? 特別的TIME_WAIT狀態(tài):
?
?? 從以上TCP連接關(guān)閉的狀態(tài)轉(zhuǎn)換圖可以看出,主動關(guān)閉的一方在發(fā)送完對對方FIN報(bào)文的確認(rèn)(ACK)報(bào)文后,會進(jìn)入TIME_WAIT狀態(tài)。TIME_WAIT狀態(tài)也稱為2MSL狀態(tài)。
?
?? 什么是2MSL?MSL即Maximum Segment Lifetime,也就是報(bào)文最大生存時間,引用《TCP/IP詳解》中的話:“它(MSL)是任何報(bào)文段被丟棄前在網(wǎng)絡(luò)內(nèi)的最長時間。”那么,2MSL也就是這個時間的2倍。其實(shí)我覺得沒必要把這個MSL的確切含義搞明白,你所需要明白的是,當(dāng)TCP連接完成四個報(bào)文段的交換時,主動關(guān)閉的一方將繼續(xù)等待一定時間(2-4分鐘),即使兩端的應(yīng)用程序結(jié)束。你可以寫代碼試試,然后用setstat查看下。
?
?? 為什么需要2MSL?根據(jù)《TCP/IP詳解》和《The TCP/IP Guide》中的說法,有兩個原因:
?? 其一,保證發(fā)送的ACK會成功發(fā)送到對方,如何保證?我覺得可能是通過超時計(jì)時器發(fā)送。這個就很難用代碼演示了。
?? 其二,報(bào)文可能會被混淆,意思是說,其他時候的連接可能會被當(dāng)作本次的連接。直接引用《The TCP/IP Guide》的說法:The second is to provide a “buffering period” between the end of this connection and any subsequent ones. If not for this period, it is possible that packets from different connections could be mixed, creating confusion.
?
?? TIME_WAIT狀態(tài)所帶來的影響:
?? 當(dāng)某個連接的一端處于TIME_WAIT狀態(tài)時,該連接將不能再被使用。事實(shí)上,對于我們比較有現(xiàn)實(shí)意義的是,這個端口將不能再被使用。某個端口處于TIME_WAIT狀態(tài)(其實(shí)應(yīng)該是這個連接)時,這意味著這個TCP連接并沒有斷開(完全斷開),那么,如果你bind這個端口,就會失敗。對于服務(wù)器而言,如果服務(wù)器突然crash掉了,那么它將無法再2MSL內(nèi)重新啟動,因?yàn)閎ind會失敗。解決這個問題的一個方法就是設(shè)置socket的SO_REUSEADDR選項(xiàng)。這個選項(xiàng)意味著你可以重用一個地址。
?
?? 對于TIME_WAIT的插曲:
?? 當(dāng)建立一個TCP連接時,服務(wù)器端會繼續(xù)用原有端口監(jiān)聽,同時用這個端口與客戶端通信。而客戶端默認(rèn)情況下會使用一個隨機(jī)端口與服務(wù)器端的監(jiān)聽端口通信。有時候,為了服務(wù)器端的安全性,我們需要對客戶端進(jìn)行驗(yàn)證,即限定某個IP某個特定端口的客戶端。客戶端可以使用bind來使用特定的端口。對于服務(wù)器端,當(dāng)設(shè)置了SO_REUSEADDR選項(xiàng)時,它可以在2MSL內(nèi)啟動并listen成功。但是對于客戶端,當(dāng)使
用bind并設(shè)置SO_REUSEADDR時,如果在2MSL內(nèi)啟動,雖然bind會成功,但是在windows平臺上connect會失敗。而在linux上則不存在這個問題。(我的實(shí)驗(yàn)平臺:winxp, ubuntu7.10)
??? 要解決windows平臺的這個問題,可以設(shè)置SO_LINGER選項(xiàng)。SO_LINGER選項(xiàng)決定調(diào)用close時TCP的行為。SO_LINGER涉及到linger結(jié)構(gòu)體,如果設(shè)置結(jié)構(gòu)體中l(wèi)_onoff為非0,l_linger為0,那么調(diào)用close時TCP連接會立刻斷開,TCP不會將發(fā)送緩沖中未發(fā)送的數(shù)據(jù)發(fā)送,而是立即發(fā)送一個RST報(bào)文給對方,這個時候TCP連接就不會進(jìn)入TIME_WAIT狀態(tài)。如你所見,這樣做雖然解決了問題,但是并不安全。通過以上方式設(shè)置SO_LINGER狀態(tài),等同于設(shè)置SO_DONTLINGER狀態(tài)。
?
??? 斷開連接時的意外:
??? 這個算不上斷開連接時的意外,當(dāng)TCP連接發(fā)生一些物理上的意外情況時,例如網(wǎng)線斷開,linux上的TCP實(shí)現(xiàn)會依然認(rèn)為該連接有效,而windows則會在一定時間后返回錯誤信息。這似乎可以通過設(shè)置SO_KEEPALIVE選項(xiàng)來解決,不過不知道這個選項(xiàng)是否對于所有平臺都有效。
?
第三部分:常見面試題
-
- TCP協(xié)議和UDP協(xié)議的區(qū)別是什么
- TCP協(xié)議是有連接的,有連接的意思是開始傳輸實(shí)際數(shù)據(jù)之前TCP的客戶端和服務(wù)器端必須通過三次握手建立連接,會話結(jié)束之后也要結(jié)束連接。而UDP是無連接的
- TCP協(xié)議保證數(shù)據(jù)按序發(fā)送,按序到達(dá),提供超時重傳來保證可靠性,但是UDP不保證按序到達(dá),甚至不保證到達(dá),只是努力交付,即便是按序發(fā)送的序列,也不保證按序送到。
- TCP協(xié)議所需資源多,TCP首部需20個字節(jié)(不算可選項(xiàng)),UDP首部字段只需8個字節(jié)。
- TCP有流量控制和擁塞控制,UDP沒有,網(wǎng)絡(luò)擁堵不會影響發(fā)送端的發(fā)送速率
- TCP是一對一的連接,而UDP則可以支持一對一,多對多,一對多的通信。
- TCP面向的是字節(jié)流的服務(wù),UDP面向的是報(bào)文的服務(wù)。
- TCP介紹和UDP介紹
- 請?jiān)敿?xì)介紹一下TCP協(xié)議建立連接和終止連接的過程?
- 助于理解的一段話
- 兩幅圖(來源):
- 建立連接:三次握手
- 關(guān)閉連接:四次揮手
- 三次握手建立連接時,發(fā)送方再次發(fā)送確認(rèn)的必要性?
-
- 主 要是為了防止已失效的連接請求報(bào)文段突然又傳到了B,因而產(chǎn)生錯誤。假定出現(xiàn)一種異常情況,即A發(fā)出的第一個連接請求報(bào)文段并沒有丟失,而是在某些網(wǎng)絡(luò)結(jié) 點(diǎn)長時間滯留了,一直延遲到連接釋放以后的某個時間才到達(dá)B,本來這是一個早已失效的報(bào)文段。但B收到此失效的連接請求報(bào)文段后,就誤認(rèn)為是A又發(fā)出一次 新的連接請求,于是就向A發(fā)出確認(rèn)報(bào)文段,同意建立連接。假定不采用三次握手,那么只要B發(fā)出確認(rèn),新的連接就建立了,這樣一直等待A發(fā)來數(shù)據(jù),B的許多 資源就這樣白白浪費(fèi)了。
-
- 四次揮手釋放連接時,等待2MSL的意義?
-
- 第 一,為了保證A發(fā)送的最有一個ACK報(bào)文段能夠到達(dá)B。這個ACK報(bào)文段有可能丟失,因而使處在LAST-ACK狀態(tài)的B收不到對已發(fā)送的FIN和ACK 報(bào)文段的確認(rèn)。B會超時重傳這個FIN和ACK報(bào)文段,而A就能在2MSL時間內(nèi)收到這個重傳的ACK+FIN報(bào)文段。接著A重傳一次確認(rèn)。
- 第二,就是防止上面提到的已失效的連接請求報(bào)文段出現(xiàn)在本連接中,A在發(fā)送完最有一個ACK報(bào)文段后,再經(jīng)過2MSL,就可以使本連接持續(xù)的時間內(nèi)所產(chǎn)生的所有報(bào)文段都從網(wǎng)絡(luò)中消失。
-
- TCP協(xié)議和UDP協(xié)議的區(qū)別是什么
?
-
- 常見的應(yīng)用中有哪些是應(yīng)用TCP協(xié)議的,哪些又是應(yīng)用UDP協(xié)議的,為什么它們被如此設(shè)計(jì)?
- 以下應(yīng)用一般或必須用udp實(shí)現(xiàn)?
- 多播的信息一定要用udp實(shí)現(xiàn),因?yàn)閠cp只支持一對一通信。
- 如果一個應(yīng)用場景中大多是簡短的信息,適合用udp實(shí)現(xiàn),因?yàn)閡dp是基于報(bào)文段的,它直接對上層應(yīng)用的數(shù)據(jù)封裝成報(bào)文段,然后丟在網(wǎng)絡(luò)中,如果信息量太大,會在鏈路層中被分片,影響傳輸效率。
- 如果一個應(yīng)用場景重性能甚于重完整性和安全性,那么適合于udp,比如多媒體應(yīng)用,缺一兩幀不影響用戶體驗(yàn),但是需要流媒體到達(dá)的速度快,因此比較適合用udp
- 如果要求快速響應(yīng),那么udp聽起來比較合適
- 如果又要利用udp的快速響應(yīng)優(yōu)點(diǎn),又想可靠傳輸,那么只能考上層應(yīng)用自己制定規(guī)則了。
- 常見的使用udp的例子:ICQ,QQ的聊天模塊。
- 以qq為例的一個說明(轉(zhuǎn)載自知乎)
- 以下應(yīng)用一般或必須用udp實(shí)現(xiàn)?
- 常見的應(yīng)用中有哪些是應(yīng)用TCP協(xié)議的,哪些又是應(yīng)用UDP協(xié)議的,為什么它們被如此設(shè)計(jì)?
登陸采用TCP協(xié)議和HTTP協(xié)議,你和好友之間發(fā)送消息,主要采用UDP協(xié)議,內(nèi)網(wǎng)傳文件采用了P2P技術(shù)。總來的說:?
1.登陸過程,客戶端client 采用TCP協(xié)議向服務(wù)器server發(fā)送信息,HTTP協(xié)議下載信息。登陸之后,會有一個TCP連接來保持在線狀態(tài)。?
2.和好友發(fā)消息,客戶端client采用UDP協(xié)議,但是需要通過服務(wù)器轉(zhuǎn)發(fā)。騰訊為了確保傳輸消息的可靠,采用上層協(xié)議來保證可靠傳輸。如果消息發(fā)送失敗,客戶端會提示消息發(fā)送失敗,并可重新發(fā)送。?
3.如果是在內(nèi)網(wǎng)里面的兩個客戶端傳文件,QQ采用的是P2P技術(shù),不需要服務(wù)器中轉(zhuǎn)。
總結(jié)
以上是生活随笔為你收集整理的三次握手和四次挥手详细介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小县城最缺的生意有哪些 开这几种店最
- 下一篇: 为什么要用TypeScript