1. /* Prepare to accept connections on socket FD.
  2. N connection requests will be queued before further requests are refused.
  3. Returns 0 on success, -1 for errors. */
  4. extern int listen (int __fd, int __n) __THROW;

listen函数把主动连接socket变为被动连接的socket,使得这个socket可以接受其它socket的连接请求,从而成为一个服务端的socket。
函数声明:

  1. int listen(int sockfd, int backlog);

返回:0-成功, -1-失败
参数sockfd是已经被bind过的socket。socket函数返回的socket是一个主动连接的socket,在服务端的编程中,程序员希望这个socket可以接受外来的连接请求,也就是被动等待客户端来连接。由于系统默认时认为一个socket是主动连接的,所以需要通过某种方式来告诉系统,程序员通过调用listen函数来完成这件事。
参数backlog,这个参数涉及到一些网络的细节,比较麻烦,填5、10都行,一般不超过30。
当调用listen之后,服务端的socket就可以调用accept来接受客户端的连接请求。
返回值:成功则返回0,失败返回-1,错误原因存于errno 中。
listen函数一般不会返回错误。

参数backlog

https://zhuanlan.zhihu.com/p/104874605
backlog: an accumulation of uncompleted work or matters needing to be dealt with. (累计未完成的待处理事件)

socket中的backlog

在socket编程中listen函数的第二个参数为backlog,用于服务器编程。

  1. listen(sock, backlog);

listen() - 图1
根据上述的状态图中的黑线,我们知道处于LISTEN状态的服务端socket收到SYN,建立一个新的状态为SYN_REVD的连接。SYN_REVD是一种半连接状态,而当收到客户端的ACK时,则进入ESTABLISHED状态。 由于三次握手的原因,连接的发起过程中,服务器的连接状态要经过SYN_REVD和ESTABLISHED两个状态。如何保存这两种状态的连接,不同系统有不同的实现。
在FressBSD中backlog就是描述状态为SYN_REVD和ESTABLISHED的所有连接最大数量。
而Linux系统中,则使用两个队列syn queue, accept queue分别存储状态为SYN_REVD和ESTABLISHED的连接,并且在linux2.2及以后,backlog表示accept queue的大小,而syn queue大小由 /proc/sys/net/ipv4/tcp_max_syn_backlog配置。
最后通过系统调用 accept 去从accept queue中获取建立完成的连接。 在开发服务端程序时,我们可以根据CPU性能和处理的复杂程度选择backlog来控制accept queue的大小。而syn queue更多时候取决于网络的流量。例如网络流量较大,但是处理较快可以减小syn queue。而流量较小时可以增大syn queue以接受更多的连接。

image.png

可以用 netstat -na来查看socket端口TCP链接状态

内核参数somaxconn

全称:socket max connections 位置:/proc/sys/net/core/somaxconn 这是系统层面对于backlog的控制,实际上accept queue的大小 = min(somaxconn, backlog)。因此在listen这个系统调用层面,backlog最终还是受限于somaxconn。

查看队列

  1. ss -l
  2. Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
  3. tcp LISTEN 0 128 [::]:ssh [::]:*

在LISTEN状态下 Recv-Q 表示当前accept queue中的已连接数。Send-Q 表示总大小。