Linux TCP socket 开发中 listen backlog 的含义

TCP socket 服务开发的4个步骤 socket->bind->listen->accept
调用listen函数时,有一个backlog参数.

int listen(int sockfd, int backlog);

FreeBSD 和 Linux的实现有些不同, 本文讨论Linux.
在Linux中backlog表示已完成(ESTABLISHED)且未accept的队列大小.

TCP连接创建过程
服务器收到客户端SYN包,发送SYN+ACK包后,在内存创建一个状态为SYN_RCVD 的连接,放入未完成队列,这个队列的大小可通过/proc/sys/net/ipv4/tcp_max_syn_backlog设置.

服务器收到客户端的ACK包后,该连接的状态由SYN_RCVD改为ESTABLISHED,并移到已完成队列.
服务器程序调用accept后,该连接移除已完成队列, 由内核交给程序控制.

TCP 三次握手在应用程序accept之前由内核完成. 应用程序调用accept只是获取已经完成的连接.

已完成队列满后
通常未完成队列的长度大于已完成队列.
已完成队列满后, 当服务器收到来自客户端的ACK包时
如果 /proc/sys/net/ipv4/tcp_abort_on_overflow 设为 1, 直接回RST包,结束连接.
否则忽视ACK包.
内核有定时器管理未完成队列,对于由于网络原因没收到ACK包或是收到ACK包后被忽视的SYN_RCVD连接重发SYN+ACK包, 最多重发次数由/proc/sys/net/ipv4/tcp_synack_retries 设定.

backlog 即上述已完成队列的大小, 这个设置是个参考值,不是精确值. 内核会做些调整, 大于/proc/sys/net/core/somaxconn, 则取somaxconn的值

未完成队列满后
如果启用syncookies (net.ipv4.tcp_syncookies = 1),新的连接不进入未完成队列,不受影响.
否则,服务器不在接受新的连接.

SYN 洪水攻击(syn flood attack)
通过伪造IP向服务器发送SYN包,塞满服务器的未完成队列,服务器发送SYN+ACK包 没回复,反复SYN+ACK包,使服务器不可用.

启用syncookies 是简单有效的抵御措施.
启用syncookies,仅未完成队列满后才生效.

参考:
http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html
http://blog.dubbelboer.com/2012/04/09/syn-cookies.html
http://blog.csdn.net/justlinux2010/article/details/8604676

推荐阅读更多精彩内容