TCP listen() Queue
Introduction
Because of the 3-way handshake used by TCP,
an incoming connection goes through an intermediate state SYN RECEIVED
before it reaches the ESTABLISHED state
and can be returned by the accept() syscall to the application.
This means that a TCP/IP stack has two options
to implement the backlog queue for a socket in LISTEN state:
- The implementation uses a single queue,
the size of which is determined by the
backlogargument of thelisten()syscall. When aSYNpacket is received, it sends back aSYN/ACKpacket and adds the connection to the queue. When the correspondingACKis received, the connection changes its state toESTABLISHEDand becomes eligible for handover to the application. This means that the queue can contain connections in two different state:SYN RECEIVEDandESTABLISHED. Only connections in the latter state can be returned to the application by theaccept()syscall. - The implementation uses two queues, a
SYNqueue(or incomplete connection queue) and an accept queue (or complete connection queue). Connections in stateSYN RECEIVEDare added to theSYNqueue and later moved to the accept queue when their state changes toESTABLISHED, i.e. when theACKpacket in the 3-way handshake is received. As the name implies, theaccept()call is then implemented simply to consume connections from the accept queue. In this case, thebacklogargument of thelisten()syscall determines the size of the accept queue.
Historically, BSD derived TCP implementations use the first approach.
That choice implies that when the maximum backlog is reached,
the system will no longer send back SYN/ACK packets in response to SYN packets.
Usually the TCP implementation will simply drop the SYN packet
(instead of responding with a RST packet) so that the client will retry.
On Linux, things are different, as mentioned in the man page of the listen() syscall:
The behavior of the backlog argument on TCP sockets changed with Linux 2.2.
Now it specifies the queue length for completely established sockets waiting to be accepted,
instead of the number of incomplete connection requests.
This means that current Linux versions use the second option with two distinct queues:
a SYN queue with a size specified by a system wide setting
and an accept queue with a size specified by the application.
System Configuration
The maximum length of the SYN queue for incomplete sockets can be set using:
/proc/sys/net/ipv4/tcp_max_syn_backlog
or
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=4096
or make the change permanently in /etc/sysctl.conf.
While the maximum length of the aceept queue for completed sockets can be set using:
/proc/sys/net/core/somaxconn
or
sudo sysctl -w net.core.somaxconn=4096
or make the change permanently in /etc/sysctl.conf.