backlog是linux下socket函数之listen的参数,当应用程序调用listen系统调用让一个socket进入LISTEN状态时,须要指定一个backlog参数。这个参数常常被描述为,新链接队列的长度限制。html
因为TCP创建链接须要进行3次握手,一个新链接在到达ESTABLISHED状态能够被accept系统调用返回给应用程序前,必须通过一个中间状态SYN RECEIVED。这意味着,TCP/IP协议栈在实现backlog队列时,有两种不一样的选择:linux
仅使用一个队列,队列规模由listen系统调用backlog参数指定。当协议栈收到一个SYN包时,响应SYN/ACK包而且将链接加进该队列。当相应的ACK响应包收到后,链接变为ESTABLISHED状态,能够向应用程序返回。这意味着队列里的链接能够有两种不一样的状态:SEND RECEIVED和ESTABLISHED。只有后一种链接才能被accept系统调用返回给应用程序。bootstrap
使用两个队列——SYN队列(待完成链接队列)和accept队列(已完成链接队列)。状态为SYN RECEIVED的链接进入SYN队列,后续当状态变动为ESTABLISHED时移到accept队列(即收到3次握手中最后一个ACK包)。顾名思义,accept系统调用就只是简单地从accept队列消费新链接。在这种状况下,listen系统调用backlog参数决定accept队列的最大规模。服务器
对于linux操做系统,内核在2.2以后的版本,tcp/ip协议实现了第二种方案,即一个syn队列,一个accept队列,syn队列的长度由系统级别设置,accept队列的长度能够由应用级别设置,tcp建连交互流程以下图所示:网络
client 端使用 connect() 向 server 端发起链接请求(发送 syn 包),此时 client 端的 TCP 的状态为 SYN_SENT。并发
server 端在收到 syn 包后,将 TCP 相关信息放到 syn queue(半链接队列)中,同时向 client 发送 syn+ack,server 端 TCP 的状态为 SYN_RCVD。socket
client 端收到 server 端的 syn+ack 后,向 server 端发送 ack,此时 client 端的 TCP 的状态为 ESTABLISHED。Server 端收到 ack 确认后,从 syn queue 里将 TCP 信息取出,并放到 accept queue(全链接队列)中,此时 server 端的 TCP 的状态为 ESTABLISHED。tcp
系统层面:somaxconn参数,能够经过编辑/proc/sys/net/core/somaxconn的值进行设置函数
应用层面:对于netty服务端来讲,经过serverbootstrap的option进行设置,即option((ChannelOption.SO_BACKLOG,number),number即为要设置的大小,类型为int高并发
backlog最终的取值为两者中的最小值,即min(backlog,somaxconn),在服务启动以后,咱们能够经过,ss -tnlp进行查看,以下图所示:
对于backlog队列的使用状况,咱们能够经过netstat进行查询,以下图所示:
当tcp_abort_on_overflow=0,直接丢弃该ACK,经过tcpdump抓包,能够看到以下的交互流程
当tcp_abort_on_overflow=1,发送RST通知client,client会报connection reset by peer
抓包查看其流程以下所示:
经过ss -tnlp 查询监听端口全链接队列的使用状况。
经过netstat查询出链接状态处于established、但未关联进程号的链接,此链接对应着源端口以及目标端口,此链接的源端口就是咱们应用程序监听的端口,即出现backlog队列溢出的端口号。