一、TCP標志位
在講TCP三次握手和四次揮手之前,先說一下TCP標志位,方便后續的理解。
簡單來說,TCP標志位的值代表了當前請求的目的。
標志位一共有6種,分別是:
-
SYN(synchronous): 發送/同步標志,用來建立連接,和下面的第二個標志位ACK搭配使用。連接開始時,SYN=1,ACK=0,代表連接開始但是未獲得響應。當連接被響應的時候,標志位會發生變化,其中ACK會置為1,代表確認收到連接請求,此時的標志位變成了 SYN=1,ACK=1。 -
ACK(acknowledgement):確認標志,表示確認收到請求。 -
PSH(push) :表示推送操作,就是指數據包到達接收端以后,不對其進行隊列處理,而是盡可能的將數據交給應用程序處理; -
FIN(finish):結束標志,用於結束一個TCP會話; -
RST(reset):重置復位標志,用於復位對應的TCP連接。 -
URG(urgent):緊急標志,用於保證TCP連接不被中斷,並且督促中間層設備盡快處理。
此外,還有兩個序號:
-
Sequence number :順序號,發送數據包中的第一個字節的序列號,一般為小寫的seq。 -
Acknowledge number:確認號,響應前面的seq,值為seq+1,可以理解為期望下次發出的序列號為seq+1;
二、TCP三次握手
1.TCP三次握手概述
所謂三次握手(Three-way Handshake),是指建立一個TCP連接時,需要客戶端和服務器總共發送3個包。 三次握手的目的是連接服務器指定端口,建立TCP連接,並同步連接雙方的順序號和確認號並交換 TCP信息
2.圖解TCP三次握手

-
第一次握手:客戶端Client發送位碼為SYN=1,隨機產生seq=x的數據包到服務器,服務器Server由SYN=1知道,客戶端Client要求建立聯機; -
第二次握手:服務器Server收到請求后要確認聯機信息,向客戶端Client發送ack=(客戶端Client請求連接時的seq)+1,SYN=1,ACK=1,產生seq=y的包,代表接收到連接請求並且向客戶端再次確認; -
第三次握手:客戶端Client收到后檢查ack是否正確,即第一次發送的seq+1,以及位碼ACK是否為1,代表收到了服務器端發過來的確認信息。之后客戶端Client會再向服務器發送ack=(服務器Server的seq+1),ACK=1,服務器Server收到后確認ack 值與ACK=1,連接建立成功。
3.針對TCP連接的安全問題:SYN攻擊
-
危害:SYN攻擊屬於DOS攻擊的一種,它利用TCP協議缺陷,通過發送大量的半連接請求,耗費CPU和內存資源。SYN攻擊除了能影響主機外,還可以危害路由器、防火牆等網絡系統,事實上SYN攻擊並不管目標是什么系統,只要這些系統打開TCP服務就可以實施。 -
原理:在三次握手過程中,服務器發送SYN-ACK(確認收到客戶端請求的連接)之后,收到客戶端的ACK(第三個包)之前的TCP連接稱為半連接(half-open connect).此時服務器處於SYN_RECV(等待客戶端相應)狀態,如果接收到客戶端的ACK,則TCP連接成功,如果未接受到,則會重發請求直至成功。SYN攻擊就是 攻擊客戶端 在短時間內偽造大量不存在的IP地址,向服務器不斷地發送SYN包,服務器回復確認包,並等待客戶的確認,由於源地址是不存在的,服務器需要不斷的重發直 至超時,這些偽造的SYN包將長時間占用未連接隊列,影響了正常的SYN,目標系統運行緩慢,嚴重者引起網絡堵塞甚至系統癱瘓。 -
檢測:檢測SYN攻擊非常的方便,當在服務器上看到大量的半連接狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN攻擊。 -
防范:主要有兩大類,一類是通過防火牆、路由器等過濾網關防護,另一類是通過加固TCP/IP協議棧防范.但必須清楚的是,SYN攻擊不能完全被阻止,我們所做的是盡可能的減輕SYN攻擊的危害,除非將TCP協議重新設計。
過濾網關防護:
-
網關超時設置 -
SYN網關 -
SYN代理
加固TCP/IP協議棧:
-
SynAttackProtect機制 -
SYN cookies技術 -
增加最大半連接數 -
縮短超時時間
三、圖解TCP四次揮手

-
客戶端Client進程發出連接釋放報文,並且停止發送數據。其中FIN=1,順序號為seq=m(等於前面已經傳送過來的數據的最后一個字節的序號加1),此時,客戶端Client進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即使不攜帶數據,也要消耗一個序號。 -
服務器Server收到連接釋放報文,發出確認報文,ACK=1,ack=m+1,並且帶上自己的順序號seq=n,此時,服務器Server就進入了CLOSE-WAIT(關閉等待)狀態。TCP服務器通知高層的應用進程,客戶端Client向服務器的方向就釋放了,這時候處於半關閉狀態,即客戶端Client已經沒有數據要發送了,但是服務器Server若發送數據,客戶端Client依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。 -
客戶端Client收到服務器Server的確認信息后,此時,客戶端Client就進入FIN-WAIT-2(終止等待2)狀態,等待服務器Server發送連接釋放報文(在這之前還需要接受服務器Server發送的最后的數據)。 -
服務器Server將最后的數據發送完畢后,就向客戶端發送連接釋放報文,FIN=1,ack=m+1,由於在半關閉狀態,服務器Server很可能又發送了一些數據,假定此時的順序號為seq=p,此時,服務器Server就進入了LAST-ACK(最后確認)狀態,等待客戶端Client的確認。 -
客戶端Client收到服務器Server的連接釋放報文后,必須發出確認,ACK=1,ack=p+1,而自己的順序號是seq=m+1,此時,客戶端Client就進入了TIME-WAIT(時間等待)狀態。注意此時TCP連接還沒有釋放,必須經過2*MSL(最長報文段壽命)的時間后,當客戶端Client撤銷相應的TCB(保護程序)后,才進入CLOSED狀態。 -
服務器Server只要收到了客戶端Client發出的確認,立即進入CLOSED狀態。同樣,撤銷TCB后,就結束了這次的TCP連接。可以看到,服務器Server結束TCP連接的時間要比客戶端Client早一些。
四、常見面試題
1.為什么連接的時候是三次握手,關閉的時候卻是四次握手?
答:因為當客戶端發起關閉連接的請求時,發出的FIN,僅代表客戶端沒有需要發送給服務器端的數據了。而如果服務器端如果仍有數據需要發送給客戶端的話,響應報文ACK和結束報文FIN則就不能同時發送給客戶端了。此時,服務器端會先返回一個響應報文,代表接收到了客戶端發出的FIN請求,而后在數據傳輸完了之后,再發出FIN請求,表示服務器端已經准備好斷開連接了。所以關閉連接的時候是四次握手。
2.為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
答:按照前面所說,當四個報文全部發送完畢后,理論上就算是結束了。但是實際情況往往不會那么可靠,比如最后一條報文發出后丟失了,那么服務器端就不會接收到這一報文,每隔一段時間,服務器端會再次發出FIN報文,此時如果客戶端已經斷開了,那么就無法響應服務器的二次請求,這樣服務器會繼續發出FIN報文,從而變成了死循環。所以需要設置一個時間段,如果在這個時間段內接收到了服務器端的再次請求,則代表客戶端發出的ACK報文沒有接收成功。反之,則代表服務器端成功接收響應報文,客戶端進入CLOSED狀態,此次連接成功關閉。而這個時間,就規定為了2MSL,即客戶端發出ACK報文到服務器端的最大時間 + 服務器沒有接收到ACK報文再次發出FIN的最大時間 = 2MSL
3.為什么不能用兩次握手進行連接?
答:三次握手有兩個重要的功能,一是要雙方做好發送數據的准備工作且雙方都知道彼此已准備好,二要允許雙方就初始順序號進行協商,這個順序號在握手過程中被發送和確認。如果改為了兩次握手,是有可能發生死鎖的。在兩次握手的設定下,服務器端在成功接受客戶端的連接請求SYN后,向客戶端發出ACK確定報文時,如果因為網絡原因客戶端沒有接收到,則會一直等待服務器端的ACK報文,而服務器端則認為連接成功建立了,便開始向客戶端發送數據。但是客戶端因為沒有收到服務器端的ACK報文,且不知道服務器的順序號seq,則會認為連接未成功建立,忽略服務器發出的任何數據。如此客戶端一直等待服務器端的ACK報文,而服務器端因為客戶端一直沒有接收數據,而不斷地重復發送數據,從而造成死鎖。
4.如果已經建立了連接,但是客戶端突然出現故障了怎么辦?
答:TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求后都會重新復位這個計時器,時間通常是設置為2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以后每隔75秒鍾發送一次。若一連發送10個探測報文仍然沒反應,服務器就認為客戶端出了故障,接着就關閉連接。
你好!我是 JHCan333,公眾號:愛生活的前端狗的作者。公眾號專注前端工程師方向,包括但不限於技術提高、職業規划、生活品質、個人理財等方面,會持續發布優質文章,從各個方面提升前端開發的幸福感。關注公眾號,我們一起向前走!