面試題總結(一)、TCP協議
宣告:本文主要探討當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的情況