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
表示全連接隊列的使用大小,超過最大值則會溢出。
關注作者微信公衆號: