天天看點

TCP協定中的backlog參數

同步滾動:關

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參數

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)