TCP的全连接和半连接队列
当服务端调用listen函数监听端口的时候,内核会为每个监听的socket创建两个队列:
-
半连接队列(syn queue):客户端发送
SYN
包,服务端收到后回复SYN+ACK
后,服务端进入SYN_RCVD
状态,这个时候的socket会放到半连接队列。 -
全连接队列(accept queue):当服务端收到客户端的ACK后,socket会从半连接队列移出到全连接队列。当调用accpet函数的时候,会从全连接队列的头部返回可用socket给用户进程。
半连接队列
半连接队列的大小由/proc/sys/net/ipv4/tcp_max_syn_backlog
控制,Linux的默认是1024。
当服务端发送SYN_ACK
后将会开启一个定时器,如果超时没有收到客户端的ACK
,将会重发SYN_ACK
包。重传的次数由/proc/sys/net/ipv4/tcp_synack_retries
控制,默认是5次。
全连接队列
全连接队列的大小通过/proc/sys/net/core/somaxconn
指定,在使用listen函数时,内核会根据传入的backlog
参数与系统参数somaxconn,取二者的较小值。
listen函数:
- ounter(line
int listen(int sockfd, int backlog)
Nginx和Redis默认的backlog值等于511,Linux默认的backlog 为 128,Java默认的backlog等于50
默认情况下,全连接队列满以后,服务端会忽略客户端的 ACK,随后会重传SYN+ACK
,也可以修改这种行为,这个值由/proc/sys/net/ipv4/tcp_abort_on_overflow
决定。
-
tcp_abort_on_overflow为0表示三次握手最后一步全连接队列满以后服务端会丢掉客户端发过来的ACK,服务端随后会进行重传 SYN+ACK
。 -
tcp_abort_on_overflow为1表示全连接队列满以后服务端发送RST给客户端,直接释放资源。
syn_flood攻击
命令查看
netstat -s
- ounter(line
- ounter(line
- ounter(line
- ounter(line
- ounter(line
netstat -s | egrep "listen|LISTEN"
// 全连接队列溢出次数
667399 times the listen queue of a socket overflowed
// 半连接队列溢出次数
667399 SYNs to LISTEN sockets dropped
ss -lnt
- ounter(line
- ounter(line
- ounter(line
[root@mcs opt]# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 *:8080 *:*
在listen
状态下,Send-Q
表示全连接队列大小的最大值,Recv-Q
表示全连接队列的使用大小,超过最大值则会溢出。
关注作者微信公众号: