前面兩篇文章介紹了tcp狀態變遷,以及通過實驗演示了客戶端和服務端的正常狀態變遷。
下面就來看看tcp狀態變遷過程中的幾個特殊狀態。
在tcp連線建立的過程中,當服務端接收到[syn]包後,就會傳送[syn, ack]包,然後進入syn_rcvd狀態。
根據前面文章的介紹,伺服器的上述行為被稱為被動開啟,並且會等待來自客戶的的[ack]包來完成tcp連線的建立。但是,如果此時客戶端沒有響應,服務端就會超時重傳[syn, ack]包。
回想一下我們在"動手學習tcp: 環境搭建"一文中使用的例子,這個例子就只是客戶端向服務端傳送乙個tcp連線建立請求包,然後就進入等待狀態了。
讓我們再次執行這個例子,通過wireshark抓包可以看到,虛擬機器中的服務端進行了五次超時重傳,間隔為3s,6s,12s,24s,一共45s;但是,當第五個[syn, ack]包傳送後,伺服器將會繼續等待48s,最終第五次重傳也超時了。
在伺服器重傳這段時間,通過虛擬機器中的命令列執行 netstat -anp tcp | findstr "
192.168.56
" 命令,會看到伺服器處於syn_rcvd狀態。
從上面的實驗結果可以看到,當服務端收到客戶端的tcp連線請求後,會傳送[syn, ack]包,進入syn_rcvd狀態。如果沒有收到客戶端的確認,伺服器會嘗試重傳,並保持syn_rcvd狀態一段時間(通常是30秒到2分鐘)。
由於服務端的syn_rcvd狀態,就有了syn flood攻擊。
所謂的syn flood攻擊就是,惡意的客戶端給服務端發了乙個syn後,就下線了,於是伺服器需要預設等93s(通常是30秒到2分鐘,上面的例子是93s)才會斷開連線。
這樣,攻擊者就可以把伺服器的syn連線的佇列耗盡,讓正常的連線請求不能處理。
對於如何避免syn flood攻擊,服務端有很多設定方式,這裡就不介紹了,有興趣可以網上查查。
在客戶端的正常狀態變遷中,客戶端主動終止tcp連線,然後就會從time_wait狀態到closed狀態。
time_wait狀態也稱為2msl(maximum segment lifetime)等待狀態,這個設定是tcp中4中定時器之一(另外的3個定時器後面介紹)。
rfc793定義了msl為2分鐘,但是在實現中,msl一般為30秒,1分鐘或者兩分鐘。
之所以有乙個time_wait狀態,而不是直接轉換成closed狀態,主要有下面兩個原因:
客戶端傳送最後的確認[ack]後進入time_wait狀態,但是這個[ack]包可能會丟失;這種情況下服務端會重傳[fin, ack]。也就是說,time_wait停留2被的msl就是為了讓tcp再次傳送最後的[ack]以方式這個[ack]丟失。
防止上一次連線中的包,迷路後重新出現,影響新連線(經過2msl,上一次連線中所有的重複包都會消失)
當一端進入time_wait狀態後,所產生的效果就是該埠在2msl這段時間中不能被再次使用。
看乙個實驗例子,由於 作業系統不能檢測到pcap.net實現的客戶端的tcp連線狀態,所以通過python實現了乙個簡單的socket客戶端,並強制指定客戶端的埠號為3333:
from socket import *當程式執行後,可以通過netstat命令看到客戶端顯示進入"established"狀態,當終止連線後,就進入了"time_wait"狀態。import
time
client_addr = ("
192.168.56.101
", 3333)
server_addr = ("
192.168.56.102
", 8081)
bufsiz = 1024client =socket(af_inet, sock_stream)
client.bind(client_addr)
client.connect(server_addr)
"client connect to server
"quit after 5 seconds
"time.sleep(5)
client.close()
這時,當再次執行客戶端程式的時候,就會遇到下面的異常,提示埠被占用:
從上面的介紹可以看到,主動終止tcp連線的一端會進入time_wait狀態,該端tcp連線的埠將在2msl時間中不可用。
如果在大併發的短連線情況下,time_wait 就會很多,系統的可用埠資源就會面臨耗盡的情況。
這也就說明了http的keepalive對http伺服器是多麼的重要,在設定keepalive的情況下,瀏覽器會重用乙個tcp連線來處理多個http請求,減緩time_wait帶來的影響。
關於復位報文段,它不是乙個tcp狀態,但是確實tcp狀態變遷中不可少的一部分,所以在這裡進行簡單的介紹。
所謂復位報文段就是tcp首部中,設定rst標誌的tcp包。一般來說,無論何時乙個報文段傳送過程中遇到連線錯誤,tcp都會發出乙個[rst]包來重置該tcp連線。
一般下面情況下會經常碰到[rst]包:
這次依然執行"動手學習tcp: 環境搭建"中的例子,只是把目標埠改為"1234"。
endpointinfo endpointinfo = new執行程式,由於虛擬機器中的"1234"埠並不是乙個tcp監聽埠,所以就會收到來自虛擬機器的[rst]包:endpointinfo();
endpointinfo.sourcemac = "
08:00:27:00:c0:d5";
endpointinfo.destinationmac = "
08:00:27:70:a6:ae";
endpointinfo.sourceip = "
192.168.56.101";
endpointinfo.destinationip = "
192.168.56.102";
endpointinfo.sourceport = 3330;//
endpointinfo.destinationport = 8081;
endpointinfo.destinationport = 1234;
前面已經看到,正常終止乙個tcp連線需要進行四次揮手,這也被稱為有序釋放(orderly release)。
但是,也有情況是通過[rst]包來釋放乙個連線,這種情況被稱為異常釋放(abortive release)。
異常終止乙個連線對應用程式來說有兩個優點:
丟棄任何帶傳送資料並立即傳送復位報文段
[rst]包的接收方能夠區分另一端執行的是異常關閉還是正常關閉。
syn_rcvd狀態會使服務端的特定埠,在一段時間內重傳[syn, ack]包,直到超時或者客戶端有相應;在該端時間內,伺服器的該埠被占用。time_wait狀態則是,主動關閉tcp連線的一端,會保持2msl的時間後,才進入closed狀態。
後半部分簡單介紹了復位報文段,以及復位報文段經常使用的情況。
動手學習TCP TCP特殊狀態
前面兩篇文章介紹了tcp狀態變遷,以及通過實驗演示了客戶端和服務端的正常狀態變遷。下面就來看看tcp狀態變遷過程中的幾個特殊狀態。在tcp連線建立的過程中,當服務端接收到 syn 包後,就會傳送 syn,ack 包,然後進入syn rcvd狀態。根據前面文章的介紹,伺服器的上述行為被稱為被動開啟,並...
動手學深度學習
線性回歸的基本要素 模型 為了簡單起見,這裡我們假設 只取決於房屋狀況的兩個因素,即面積 平方公尺 和房齡 年 接下來我們希望探索 與這兩個因素的具體關係。線性回歸假設輸出與各個輸入之間是線性關係 price warea area wage age b price warea area wage a...
動手學習深度學習(筆記一)
應用深度學習需要思考的問題 1.問題的動機和特點 2.將大量不同型別神經網路層通過特定的方式組合在一起的模型背後的數字原理 3.在原始資料上擬合極複雜的深層模型的優化演算法 4.有效訓練模型 避免數值計算陷阱以及充分利用硬體效能所需的工程技能 5.為解決方案挑選合適的變數 超引數 組合的經驗。時至今...