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
backlog
argument of thelisten()
syscall. When aSYN
packet is received, it sends back aSYN
/ACK
packet and adds the connection to the queue. When the correspondingACK
is received, the connection changes its state toESTABLISHED
and becomes eligible for handover to the application. This means that the queue can contain connections in two different state:SYN RECEIVED
andESTABLISHED
. Only connections in the latter state can be returned to the application by theaccept()
syscall. - The implementation uses two queues, a
SYN
queue(or incomplete connection queue) and an accept queue (or complete connection queue). Connections in stateSYN RECEIVED
are added to theSYN
queue and later moved to the accept queue when their state changes toESTABLISHED
, i.e. when theACK
packet 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, thebacklog
argument 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
.