同步滾動:關
backlog參數的含義
TCP建立連接配接是要進行三次握手,但是否完成三次握手後,伺服器就處理(accept)呢?
backlog其實是一個連接配接隊列,在Linux核心2.2之前,backlog大小包括半連接配接狀态和全連接配接狀态兩種隊列大小。
- 半連接配接狀态為:伺服器處于Listen狀态時收到用戶端SYN封包時放入半連接配接隊列中,即SYN queue(伺服器端口狀态為:SYN_RCVD)。
- 全連接配接狀态為:TCP的連接配接狀态從伺服器(SYN+ACK)響應用戶端後,到用戶端的ACK封包到達伺服器之前,則一直保留在半連接配接狀态中;當伺服器接收到用戶端的ACK封包後,該條目将從半連接配接隊列搬到全連接配接隊列尾部,即 accept queue (伺服器端口狀态為:ESTABLISHED)。
在Linux核心2.2之後,分離為兩個backlog來分别限制半連接配接(SYN_RCVD狀态)隊列大小和全連接配接(ESTABLISHED狀态)隊列大小。
- SYN queue 隊列長度由 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,預設為2048。
- Accept queue 隊列長度由 /proc/sys/net/core/somaxconn 和使用listen函數時傳入的參數,二者取最小值。預設為128。在Linux核心2.4.25之前,是寫死在代碼常量 SOMAXCONN ,在Linux核心2.4.25之後,在配置檔案 /proc/sys/net/core/somaxconn 中直接修改,或者在 /etc/sysctl.conf 中配置 net.core.somaxconn = 128 。
兩個隊列在連接配接過程中所處的位置如下圖所示:
tcp_backlog.png
如何檢視監聽狀态
chris@chris-VirtualBox:/media/sf_share/myspace$ netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:5555 *:* LISTEN
tcp 0 0 chris-VirtualBox:domain *:* LISTEN
tcp 0 0 localhost:ipp *:* LISTEN
tcp6 0 0 ip6-localhost:ipp [::]:* LISTEN
udp 0 0 *:mdns *:*
udp 0 0 *:42226 *:*
udp 0 0 *:57698 *:*
udp 0 0 *:ipp *:*
udp 0 0 chris-VirtualBox:domain *:*
udp 0 0 *:bootpc *:*
udp6 0 0 [::]:mdns [::]:*
udp6 0 0 [::]:38317 [::]:*
raw6 0 0 [::]:ipv6-icmp [::]:*
Recv-Q & Send-Q
先看下man netstat中的說明:
- Recv-Q:The count of bytes not copied by the user program connected to this socket.
- Send-Q:The count of bytes not acknowledged by the remote host.
這裡有一篇關于這兩個隊列的分析文章,https://www.cnblogs.com/leezhxing/p/5329786.html,結論是這樣,要區分LISTEN狀态和其他狀态:
- LISTEN 狀态: Recv-Q 表示的目前等待服務端調用 accept 完成三次握手的 listen backlog 數值,也就是說,當用戶端通過 connect() 去連接配接正在 listen() 的服務端時,這些連接配接會一直處于這個 queue 裡面直到被服務端 accept();Send-Q 表示的則是最大的 listen backlog 數值,這就就是上面提到的 min(backlog, somaxconn) 的值。
- 其餘狀态: 非 LISTEN 狀态之前了解的沒有問題。Recv-Q 表示 receive queue 中的 bytes 數量;Send-Q 表示 send queue 中的 bytes 數值。
在我的機器上做了下驗證
- 作業系統
$ uname -a
Linux ubuntu 3.11.0-15-generic #25~precise1-Ubuntu SMP Thu Jan 30 17:39:31 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
在8888這個端口啟動一個監聽程式, 程式中不accept
- netstat指令檢視
$ netstat -apn |grep 8888
tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN 5399/thundering_her
- 打開兩個telnet連接配接
telnet 127.0.0.1 8888
- ss指令檢視
$ ss -l |grep 8888
LISTEN 2 50 127.0.0.1:8888 *:*
Send-Q為2,Recv-Q為listen中設定的值
結論:
兩個指令中Send-Q和Recv-Q的含義是不同的,
- netstat中應該是man裡面說明的含義
- ss中才是上面文章中的結論:Recv-Q 表示的目前等待服務端調用 accept 完成三次握手的 listen backlog 數值;Send-Q 表示min(backlog, somaxconn)