Socket listen() backlog 是什么?

listen() backlog 是什么?

1. Linux 服务器上的一些程序会监听特定端口.

2. 当有 client 连接到服务器的相应端口,进行完 tcp 三次握手之后,相应的连接会放到服务器相应 socket 的队列,等待服务器的应用程序调用 accept() 来读取这个连接;

3. 这个队列的长度,就是 listen() backlog.

以 apache httpd 为例。

1. httpd 会监听 80 端口;

2. 当有用户端连接到服务器的 80 端口,首先会进行 tcp 的三次握手。进行完三次握手后,这个连接会被放到 80 端口这个 socket 的队列里,等待 httpd 去获取这个连接;

3. httpd 随后会调用 accept() 来获取这个连接。这个连接被获取之后,会从这个队列里移除;

4. 这个监听 80 端口的 socket 对应的队列长度,就是 listen() backlog.

如何设定 listen() backlog?

在应用程序创建完 socket 后,可以调用 listen() 来使这个 socket 监听某个端口。调用 listen() 的时候,需要指定一个 backlog 的大小。

int listen(int sockfd, int backlog);

这个 backlog 的大小会受到系统全局设定的限制,系统全局参数 /proc/sys/net/core/somaxconn 决定了每个 listen() backlog 的上限值。如果应用程序调用 listen() 所设定的 backlog 值超出 somaxconn, backlog 会被截短为 somaxconn.

# man 2 listen
       If the backlog argument is greater than the value in /proc/sys/net/core/somaxconn,  then  it  is
       silently  truncated  to  that  value;  the default value in this file is 128.  In kernels before
       2.4.25, this limit was a hard coded value, SOMAXCONN, with the value 128.

示例程序:

server_sockfd = socket(PF_INET, SOCK_STREAM, 0);

bind(server_sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr);

listen(server_sockfd, 5); // <<--- 程序调用 listen() 来使 socket 监听相应端口。

                        // 这里 backlog 设定为 5.


// 当有用户访问这个监听的端口,内核会进行三次握手,而后应用程序调用 accept() 来获取这个连接。

// 程序调用 accept() 之后,相应连接会从 backlog 队列里移除。

client_sockfd = accept(server_sockfd, (struct sockaddr *)&remote_addr, &sin_size);
~~~

如何查看 listen() backlog?

在较高版本的内核中(测试环境 2.6.32-573.el6.x86_64),可以通过 `ss -ln` 来查看当前各 socket 的 backlog 状态。
"Recv-Q" 表示已经占用的 backlog.
"Send-Q" 表示 backlog 的总大小。

# ss -ln | head -n1 ;ss -ln | grep 8000
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port 
LISTEN     1      5                         *:8000                     *:*