1. 端口監聽
1.1 SO_REUSEADDR(端口重用)
服務端主動斷開連接以后,需要等 2 個 MSL 以后才最終釋放這個連接,重啟以后要綁定同一個端口,默認情況下,操作系統的實現都會阻止新的監聽套接字綁定到這個端口上。
TCP 連接由四元組唯一確定。{local-ip-address:local-port , foreign-ip-address:foreign-port}
TCP 要求這樣的四元組必須是唯一的,但大多數操作系統的實現要求更加嚴格,只要還有連接在使用這個本地端口,則本地端口不能被重用(bind 調用失敗)
啟用 SO_REUSEADDR 套接字選項可以解除這個限制,默認情況下這個值都為 0,表示關閉。
不一定是要處於 TIME_WAIT 才允許端口復用的,只是大多數情況下,主動關閉連接的服務端都會處於 TIME_WAIT,四次揮手中的第 3 步沒能成功,服務端此時將處於 FIN_WAIT2 狀態,此時也可以復用端口。
1.2 自連接問題
當服務需要connect一個目標端口時,系統會隨機分配一個臨時端口號用於連接目標端口;
如果此時分配的臨時端口號和監聽端口號一致,且客戶端和服務端都在同一台機器,此時就發生自連接現象;
解決方案:Linux TCP自連接問題
1.3 臨時端口號范圍
臨時修改:
vim /proc/sys/net/ipv4/ip_local_port_range
32768 6099
這兩個數字表示臨時端口號的豈止范圍
永久修改:
vim /etc/sysctl.conf
net.ipv4.ip_local_port_range = 10240 65535
2. 關閉連接
關閉連接有兩種方式
1. FIN:發送完數據后關閉連接,並確保對端收到了該報文,主動關閉時將處於TIME_WAIT兩個MSL
2. RST:強制關閉連接,不做保證
2.1 SO_LINGER(快速關閉)
SO_LINGER 啟用時,調用close()后,操作系統開啟一個定時器,在定時器期間內發送數據,定時時間到直接 RST 連接,主動關閉一方的TCP狀態跳過TIMEWAIT,直接進入CLOSED。
SO_LINGER 參數是一個 linger 結構體,代碼如下:
struct linger { int l_onoff; /* linger active */ int l_linger; /* how many seconds to linger for */ };
第一個字段 l_onoff 用來表示是否啟用 linger 特性,非 0 為啟用,0 為禁用 ,linux 內核默認為禁用。這種情況下 close 函數立即返回,操作系統負責把緩沖隊列中的數據全部發送至對端
第二個參數 l_linger 在 l_onoff 為非 0 (即啟用特性)時才會生效。
- 如果 l_linger 的值為 0,那么調用 close,close 函數會立即返回,同時丟棄緩沖區內所有數據並立即發送 RST 包重置連接
- 如果 l_linger 的值為非 0,那么此時 close 函數在阻塞直到 l_linger 時間超時或者數據發送完畢,發送隊列在超時時間段內繼續嘗試發送,如果發送完成則皆大歡喜,超時則直接丟棄緩沖區內容 並 RST 掉連接。
2.2 tcp_tw_recycle(快速回收)
默認情況下,主動關閉的一方最后發送一個確認關閉的ACK報文后處於TIME_WAIT狀態,最多等待兩個MSL若沒有收到消息后,則關閉連接。
通過減小等待的時間來提高端口利用率
vim /etc/sysctl.conf
net.ipv4.tw_recycle = 1 #啟用快速回收
net.ipv4.tcp_fin_timeout = 30 #MSL的值。默認60S
sysctl -p /etc/sysctl.conf #重新加載配置文件