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