listen

将一个未连接的套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求。调用listen导致套接字从CLOSED状态转换成LISTEN状态。

头文件

#include < sys/socket.h >

函数原型

int listen(int sockfd, int backlog)

函数说明

backlog 说明:
backlog为相应套接字排队的最大连接个数。
内核为任何一个监听套接字维护两个队列:

  • 未完成连接队列(incomplete connection queue),每个这样的SYN分节对应其中一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应TCP三次握手过程。这些套接字处于SYN_RCVD状态
  • 已完成连接队列(completed connection queue),每个已完成TCP三次握手过程的客户对应其中一项,这些套接字处于ESTABLISHED状态。
    tcp三次握手的过程
    监听套接字两队列

tcp 监听套接字的两队列
当来自客户的SYN到达时,TCP在未完成连接队列中创建一个新项,然后响应以三次握手的第二个分节:服务器的SYN响应,其中捎带对客户SYN的ACK。这一项一直保留在未完成队列中,直到三次握手的第三个分节(客户对服务器SYN的ACK)到达或者该项超时为止。如果三次握手正常完成,该项就从未完成队列移到已完成队列的队尾。当进程调用accept时,已完成连接队列的队头项将返回给进程,或者如果该队列为空,那么进程将被投入睡眠,直到TCP在该队列中放入一项才唤醒它。

在linux 2.2以前,backlog大小包括了半连接状态和全连接状态两种队列大小。linux 2.2以后,分离为两个backlog来分别限制半连接SYN_RCVD状态的未完成连接队列大小跟全连接ESTABLISHED状态的已完成连接队列大小

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

[root@iz2zecj7a5r32f2axsctb9z include]# sysctl -a | grep net.core.somaxconn
net.core.somaxconn = 128

注意:

  1. 当全队列已满,net.ipv4.tcp_abort_on_overflow = 0时,丢弃ack,并重发SYN+ACK, 重试次数为 net.ipv4.tcp_synack_retries。
  2. 当全队列已满,net.ipv4.tcp_abort_on_overflow = 1时,则收到ACK后,发送RST段关闭连接。

backlog太小,在高并发场景下,客户端的ACK将被丢弃,并出发服务端重新发送SYN+ACK,客户端出现大量连接失败的情况。

backlog太大,会产生太多的socket连接堆积,连接超时后,会导致wirte broken pipe错误

返回值

成功返回0 失败返回-1

文档更新时间: 2021-02-26 19:09   作者:周国强