TCP 建立連接為什麽要握 3 次手?
上次已經說過,沒有協議,不成方圓,計算機之間的通信更是依賴於協議。今天就重點分析一下 TCP 協議。
傳輸控制協議 TCP 是一種面向連接的、可靠的、基於字節流的傳輸層通信協議,由IETF的RFC 793定義。在簡化的計算機網絡 OSI 模型中,它完成第四層傳輸層所指定的功能,用戶數據包協議(UDP)是同一層內另一個重要的傳輸協議。
先來復習一下 OSI 的七層模型。
TCP 工作在 OSI 中的第四層——Transport 層,IP 在第三層——Network 層,ARP 在第二層——Data Link 層;在第二層上的數據,我們把它叫 Frame,在第三層上的數據叫 Packet,第四層的數據叫 Segment。 同時,我們需要知道,數據從應用層發下來,會在每一層都會加上頭部信息,進行封裝,然後再發送到數據接收端。
TCP 協議所涉及到的知識太多,沒有辦法兼顧,我主要想談談 3 次握手和 4 次揮手。TCP 的運行可以分為三個階段,建立連接、傳送數據、關閉連接。3 次握手 4 次揮手就對應著建立連接和關閉連接。
操作系統將 TCP 連接抽象為套接字表示的本地端點,作為編程接口給程序使用。在 TCP 連接的生命期內,本地端點要經歷一系列的狀態改變。我們經常會聽到面向 Socket 編程,這是後話了。
要想知道握手是怎樣進行了,我們先來看看 TCP 的報文結構。
有以下幾點需要說明
TCP 報文中沒有 IP 地址,有源端口和目的端口,IP 地址在網絡層中的 Packet 中。
Sequence Number(序號),用來標識從 TCP 發送端向 TCP 接收端發送的數據字節流,它表示在這個報文段中的的第一個數據字節在數據流中的序號;通信雙方要知道對方的初始化序號,這個號要作為以後的數據通信的序號,以保證應用層接收到的數據不會因為網絡上的傳輸的問題而亂序(TCP 會用這個序號來拼接數據)。
Acknowledgment Number(確認號)32 位確認序列號包含發送確認的一端所期望收到的下一個序號,因此,確認序號應當是上次已成功收到數據字節序號加 1。不過,只有當標誌位中的 ACK 標誌(下面介紹)為 1 時該確認序列號的字段才有效。主要用來解決不丟包的問題。
SYN,表示同步序號,用來建立連接。SYN 標誌位和 ACK 標誌位搭配使用,當連接請求的時候,SYN=1,ACK=0;連接被響應的時候,SYN=1,ACK=1。
這個標誌的數據包經常被用來進行端口掃描。掃描者發送一個只有 SYN 的數據包,如果對方主機響應了一個數據包回來 ,就表明這臺主機存在這個端口;但是由於這種掃描方式只是進行 TCP 三次握手的第一次握手,因此這種掃描的成功表示被掃描的機器不很安全,一臺安全的主機將會強制要求一個連接嚴格的進行 TCP 的三次握手。
ACK,TCP 協議規定,只有 ACK=1 時有效,也規定連接建立後所有發送的報文的 ACK 必須為 1 。
FIN,表示發送端已經達到數據末尾,也就是說雙方的數據傳送完成,沒有數據可以傳送了,發送 FIN 標誌位的 TCP 數據包後,連接將被斷開。這個標誌的數據包也經常被用於進行端口掃描。
三次握手的過程,即建立一個 TCP 連接的過程,在 Socket 編程中,這一過程由客戶端執行 connect 來觸發,整個流程如上圖所示。
第一次握手:Client 將標誌位 SYN 置為1,隨機產生一個值 seq=x,並將該數據包發送給 Server,Client 進入 SYN_SENT 狀態,等待 Server 確認。
第二次握手:Server 收到數據包後由標誌位 SYN=1 知道 Client 請求建立連接,Server 將標誌位 SYN 和 ACK 都置為1,ack=x+1,隨機產生一個值 seq=y,並將該數據包發送給 Client 以確認連接請求,Server 進入 SYN_RCVD 狀態。
第三次握手:Client 收到確認後,檢查 ack 是否為 x+1,ACK 是否為1,如果正確則將標誌位 ACK 置為1,ack=y+1,並將該數據包發送給 Server,Server 檢查 ack 是否為 y+1,ACK 是否為1,如果正確則連接建立成功,Client 和 Server 進入 ESTABLISHED 狀態,完成三次握手,隨後 Client 與 Server 之間可以開始傳輸數據了。
註意,不要搞混了 SYN、ACK 只是標誌位,seq 是序號,防止亂序,ack 是確認號,主要用來解決不丟包的問題。
四次揮手,即終止 TCP 連接,就是指斷開一個 TCP 連接時,需要客戶端和服務端總共發送4個包以確認連接的斷開。在 Socket 編程中,這一過程由客戶端或服務端任一方執行 close 來觸發。
由於 TCP 連接是全雙工的,因此,每個方向都必須要單獨進行關閉,這一原則是當一方完成數據發送任務後,發送一個 FIN 來終止這一方向的連接,收到一個 FIN 只是意味著這一方向上沒有數據流動了,即不會再收到數據了,但是在這個 TCP 連接上仍然能夠發送數據,直到對方也發送了 FIN。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉。
第一次揮手:主機1(可以使客戶端,也可以是服務器端),設置Sequence Number 和 Acknowledgment Number,向主機2發送一個FIN報文段;此時,主機1進入FIN_WAIT_1狀態;這表示主機1沒有數據要發送給主機2了;
第二次揮手:主機2收到了主機1發送的FIN報文段,向主機1回一個ACK報文段,Acknowledgment Number為Sequence Number加1;主機1進入FIN_WAIT_2狀態;主機2告訴主機1,我“同意”你的關閉請求;
第三次揮手:主機2向主機1發送FIN報文段,請求關閉連接,同時主機2進入LAST_ACK狀態;
第四次揮手:主機1收到主機2發送的FIN報文段,向主機2發送ACK報文段,然後主機1進入TIME_WAIT狀態;主機2收到主機1的ACK報文段以後,就關閉連接;此時,主機1等待2MSL後依然沒有收到回復,則證明 Server 端已正常關閉,那好,主機1也可以關閉連接了。
為什麽建立連接需要 3 次握手 ?
因為,TCP 協議要保證兩端數據的可靠傳輸,最少就要采取 3 次交互。三次是保證雙方互相明確對方能收能發的最低值。下面有個生活中的例子可以感受一下。
TCP之所以使用三次握手,完全是一種為了解決“兩軍問題”所采用的折衷的設計。所謂“兩軍問題”,就是紅軍想告訴藍軍明天下午一起對敵開火,那麽紅軍會派信使 1 號跑過去告訴藍軍,藍軍收到消息再派信使 2 號告訴紅軍收到,註意,這時藍軍並不知道紅軍是否收到藍軍的回復。因此需要紅軍收到回復再派信使 3 號告訴藍軍收到回復,而此時紅軍也不知道藍軍是否收到回復,因此藍軍收到信使 3 號的消息再派信使 4 號…
還有一個秒懂例子,看到這個真的笑死我了。但是這個例子不嚴謹哦,權當一樂就好。
三次握手:
“餵,你聽得到嗎?”
“我聽得到呀,你聽得到我嗎?”
“我能聽到你,今天balabala……”
兩次握手:
“餵,你聽得到嗎?”
“我聽得到呀”
“餵餵,你聽得到嗎?”
“草,我聽得到呀!!!!”
“你TM能不能聽到我講話啊!!餵!”
“……”
四次握手:
“餵,你聽得到嗎?”
“我聽得到呀,你聽得到我嗎?”
“我能聽到你,你能聽到我嗎?”
“……不想跟傻逼說話”
所以說,握手次數要保持剛剛好,2 次不夠,4 次多了。
SYN 攻擊
SYN 攻擊指的是,攻擊客戶端在短時間內偽造大量不存在的 IP 地址,向服務器不斷地發送 SYN 包,服務器回復確認包,並等待客戶的確認。由於源地址是不存在的,服務器需要不斷的重發直至超時,這些偽造的 SYN 包將長時間占用未連接隊列,正常的 SYN 請求被丟棄,導致目標系統運行緩慢,嚴重者會引起網絡堵塞甚至系統癱瘓。SYN 攻擊是一種典型的 DoS/DDoS 攻擊。
檢測 SYN 攻擊非常的方便,當你在服務器上看到大量的半連接狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN攻擊。
如何防禦 SYN 攻擊 ?
SYN 攻擊不能完全被阻止,除非將 TCP 協議重新設計。我們所做的是盡可能的減輕 SYN 攻擊的危害,常見的防禦 SYN 攻擊的方法有如下幾種:
縮短超時(SYN Timeout)時間
增加最大半連接數
過濾網關防護
SYN cookies 技術
TCP 建立連接為什麽要握 3 次手?