tcp源埠不是隨機的
當我們嘗試從網路伺服器獲取文件時,有時無法訪問。用 tcpdump 檢查通信後,我們看到 Source-machine 隨機選擇一個 source-port 進行通信。這應該沒問題,但“隨機選擇”並不像想像的那麼隨機。所以源埠經常在很短的時間(有時只有 2 秒)後被重用。在目標系統上,套接字處於 TIME_WAIT 狀態,因此通信被目標丟棄。問題是,為什麼伺服器選擇的源埠不夠隨機(如 3388、3345、2345、3388)。
使用帶有以下參數的 wget 時,我們能夠重新創建完全相同的行為:
wget -t 1 "xxx/test.html" -O /dev/null -o /dev/null -d --bind-address=yyy.yyy.yyy.yyy
然後系統隨機選擇埠,但不是隨機選擇埠,如果埠被重用太快,則無法進行通信(重新發送 SYN 數據包)
wget 語句的一個小修改:
wget -t 1 "xxx/test.html" -O /dev/null -o /dev/null -d
一切正常,埠被一一選擇。溝通永遠不會掛起。
因此,我們的源系統的工作方式與第一個 wget 語句完全相同,但我們需要它像第二個那樣工作,或者更隨機地選擇埠。如何更改為 TCP 通信選擇源埠的行為?
我已經在本地對此進行了測試,並且無法複製該行為。即使我將我的 linux 機器設置為僅使用兩個本地埠,我也能夠毫無問題地啟動到同一個域(內部或外部)的多個(20 多個)連接。我還通過設置 no-http-keep-alive 標頭(並通過 netstat 確認)確保遠端伺服器處於 TIME-WAIT 狀態。
我發現當使用
--bind-address
WGET 標誌時,它使用 Bind() 創建套接字,其中源 IP 是命令行上指定的任何內容,源埠是從/proc/sys/net/ipv4/ip_local_port_range
. 每當需要選擇新的源埠時,這將是前一個埠 + 2。到達源埠範圍的末尾後,它將返回到起點並再次開始以二為單位計數。當您省略該
--bind-address
標誌時,Connect() 用於建立從預設介面獲取源 IP 的套接字,並且源埠是該/proc/sys/net/ipv4/ip_local_port_range
範圍內的隨機埠。新的源埠也將從該範圍內隨機選擇。在任何一種情況下,當重用套接字時,初始序列號都會增加內部 TCP 時鐘,從而允許伺服器接受新的連接形式。這與我使用相同源埠和增加 ISN 值對 20 個連接請求的測試一致——所有這些請求都被處於 TIME-WAIT 狀態的伺服器接受。
如果我們排除 tcp_tw_recycle 引入的任何怪異,因為我不相信 Windows 伺服器上存在該選項,那麼我能想到的唯一其他事情是以下組合:
- 在您的 Linux 伺服器上配置的一個小型臨時埠範圍,這會導致在使用
--bind-interface
.- 客戶端和伺服器之間執行 TCP 序列號隨機化的防火牆或其他網路設備。因此,不能相信到達伺服器的初始序列號將大於先前的連接,並可能導致連接斷開。