聲明:本文主要探討當TCP協議出現在面試筆試場合可能會涉及的問題,每一個知識點討論力求簡潔,便於記憶,但討論深度有限,如要深入研究可點擊參考鏈接,希望對正在找工作的同學有點幫助。
一、TCP協議簡介
一般問到TCP協議的時候 最常見的是TCP連接建立和斷開的過程,也就是三次握手和四次揮手,兩張圖足矣。
1.1 三次握手
1.2 四次揮手
二、常見面試題
2.1 TCP連接階段
2.1.1 發送序號和確認序號問題
例: TCP建立連接的過程采用三次握手,已知第三次握手報文的發送序列號為1000,確認序列號為2000,請問第二次握手報文的發送序列號和確認序列號分別為?
答:看答案時請參考上面TCP連接建立的圖。
客戶端:發送X
服務端:發送Y, 確認X+1
客戶端:發送X+1(1000),確認Y+1(2000)
可以反推第二次為1999,確認1000
2.1.2 SYN Flood 攻擊原理及防御
SYN Flood是當前最流行的DoS(拒絕服務攻擊)與DDoS(分布式拒絕服務攻擊)的方式之一,這是一種利用TCP協議缺陷,發送大量偽造的TCP連接請求,從而使得被攻擊方資源耗盡(CPU滿負荷或內存不足)的攻擊方式。
原理:
問題出在TCP連接的三次握手中,惡意的攻擊者大量發送SYN報文,服務器端將為了維護一個非常大的半連接列表而消耗非常多的資源----數以萬計的半連接,即使是簡單的保存並遍歷也會消耗非常多的CPU時間和內存,何況還要不斷對這個列表中的IP進行SYN+ACK的重試。實際上如果服務器的TCP/IP棧不夠強大,最后的結果往往是堆棧溢出崩潰---即使服務器端的系統足夠強大,服務器端也將忙於處理攻擊者偽造的TCP連接請求而無暇理睬客戶的正常請求(畢竟客戶端的正常請求比率非常之小),此時從正常客戶的角度看來,服務器失去響應,這種情況我們稱作:服務器端受到了SYN Flood攻擊(SYN洪水攻擊)。
攻擊方式:
- Direct Attack 攻擊方使用固定的源地址發起攻擊,這種方法對攻擊方的消耗最小
- Spoofing Attack 攻擊方使用變化的源地址發起攻擊,這種方法需要攻擊方不停地修改源地址,實際上消耗也不大
- Distributed Direct Attack 這種攻擊主要是使用僵屍網絡進行固定源地址的攻擊
防御方法:
- 無效連接監視釋放
不停監視系統的半開連接和不活動連接,當達到一定閾值時拆除這些連接,從而釋放系統資源。 - 延緩TCB分配方法
從前面SYN Flood原理可以看到,消耗服務器資源主要是因為當SYN數據報文一到達,系統立即分配TCB,從而占用了資源。而SYN Flood由於很難建立起正常連接,因此,當正常連接建立起來后再分配TCB則可以有效地減輕服務器資源的消耗。常見的方法是使用Syn Cache和Syn Cookie技術。
Syn Cache技術:
這種技術是在收到SYN數據報文時不急於去分配TCB,而是先回應一個SYN ACK報文,並在一個專用HASH表(Cache)中保存這種半開連接信息,直到收到正確的回應ACK報文再分配TCB。
Syn Cookie技術:
Syn Cookie技術則完全不使用任何存儲資源,它使用一種特殊的算法生成Sequence Number,這種算法考慮到了對方的IP、端口、己方IP、端口的固定信息,以及對方無法知道而己方比較固定的一些信息,如MSS、時間等,在收到對方的ACK報文后,重新計算一遍,看其是否與對方回應報文中的(Sequence Number-1)相同,從而決定是否分配TCB資源。 - 使用SYN Proxy防火牆
防火牆中提供一種SYN代理的功能,主要原理是對試圖穿越的SYN請求進行驗證后才放行。
詳情請移步 SYN Flood攻擊及防御方法
2.1.3 為什么TCP建立連接要三次握手
首先得回答三次握手的目的是同步連接雙方的序列號和確認號並交換 TCP 窗口大小信息。
然后可以回答為什么兩次握手不行,兩次握手可能因為丟包而出現死鎖,假設在兩次握手場景中,C向S發送請求,S收到並發送確認請求給C,這時候S認為連接已經建立,並開始發送數據給C,但是那個確認請求丟包了,C不認為請求建立了,C當然會拒絕接受S發送來的數據,並且再去請求連接。這樣,一個資源就死鎖了。
最后回答握手當然可以四次五次一直握下去,但三次已經夠了,就沒有必要了。
總結下來一句話,主要目的防止在網絡發生延遲或者丟包的情況下浪費資源。
詳情請移步 TCP為什么要三次握手,不是兩次四次
2.2 TCP傳輸階段
2.2.1 滑動窗口以及擁塞控制
TCP協議作為一個可靠的面向流的傳輸協議,其可靠性和流量控制由滑動窗口協議保證,而擁塞控制則由控制窗口結合一系列的控制算法實現。
詳情請移步 tcp窗口滑動以及擁塞控制
2.3 TCP斷開階段
2.3.1 設置TIME_WAIT的原因
- 可靠地實現TCP全雙工連接的終止
TCP協議在關閉連接的四次握手過程中,最終的ACK是由主動關閉連接的一端(后面統稱A端)發出的,如果這個ACK丟失,對方(后面統稱B端)將重發出最終的FIN,因此A端必須維護狀態信息(TIME_WAIT)允許它重發最終的ACK。如果A端不維持TIME_WAIT狀態,而是處於CLOSED 狀態,那么A端將響應RST分節,B端收到后將此分節解釋成一個錯誤(在java中會拋出connection reset的SocketException)。
因而,要實現TCP全雙工連接的正常終止,必須處理終止過程中四個分節任何一個分節的丟失情況,主動關閉連接的A端必須維持TIME_WAIT狀態 - 允許老的重復分節在網絡中消逝
TCP分節可能由於路由器異常而“迷途“,在迷途期間,TCP發送端可能因確認超時而重發這個分節,迷途的分節在路由器修復后也會被送到最終目的地,這個遲到的迷途分節到達時可能會引起問題。在關閉“前一個連接”之后,馬上又重新建立起一個相同的IP和端口之間的“新連接”,“前一個連接”的迷途重復分組在“前一個連接”終止后到達,而被“新連接”收到了。為了避免這個情況,TCP協議不允許處於TIME_WAIT狀態的連接啟動一個新的可用連接,因為TIME_WAIT狀態持續2MSL,就可以保證當成功建立一個新TCP連接的時候,來自舊連接重復分組已經在網絡中消逝。
2.3.2 大量 TIME_WAIT 產生的原因及解決辦法
原因:對於基於TCP的HTTP協議,關閉TCP連接的是Server端,這樣,Server端會進入TIME_WAIT狀態,可想而知,對於訪問量大的Web Server,會存在大量的TIME_WAIT狀態。
解決辦法:
- 開啟socket重用,允許將TIME_WAIT的socket重新用於TCP連接
- 開啟快速回收。
2.3.3 大量CLOSE_WAIT產生的原因及解決辦法
原因:對方關閉連接之后服務器程序自己沒有進一步發出ack信號。換句話說,就是在對方連接 關閉之后,程序里 沒有檢測到,或者程序壓根就忘記了這個時候需要關閉連接,於是這個資源就一直被程序占着。
解決辦法:
具體問題具體解決,總結一句話就是在處理資源時一定要記住自己申請的資源要記得主動釋放。
詳情請移步 再談應用環境下的TIME_WAIT和CLOSE_WAIT
2.3.4 為什么TCP斷開連接要四次揮手
因為tcp是全雙工模式,接收到FIN時意味將沒有數據再發來,但是還是可以繼續發送數據。
詳情請移步 TCP為什么需要3次握手與4次揮手
2.4 其他
2.4.1 出現RST包的原因
RST:TCP首部中的6個標志比特之一,表示重置連接、復位連接。
- 服務器端口未打開而客戶端來連接時
- 在一個已關閉的SOCKET上收到數據
- 請求超時
- 提前關閉
詳細請移步 幾種TCP連接中出現RST的情況

![4220220[1].png](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvODAxNDQ2LzIwMTUwOC8yMjE2MzgwNDI1MzY2MjUucG5n.png)
![1363876245_7915[1].JPG](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvODAxNDQ2LzIwMTUwOC8yMjE2MzgwNDczODc5NDAuanBn.png)