[转帖]linux tcp 半连接队列和全连接队列

linux,tcp,连接,队列 · 浏览次数 : 0

小编点评

**内容生成排版** **1. 全连接队列最大长度** ``` # ss -antp | grep SYN-RECV | wc -l ``` **2. 半连接队列溢出统计信息** ``` # netstat -s | grep dropped     166 SYNs to LISTEN sockets dropped ``` **3. syn洪水攻击防御** ``` # echo 1 > /proc/sys/net/ipv4/tcp_syncookies # echo 1 > /proc/sys/net/ipv4/tcp_synack_retries ``` **4. TCP 半连接队列和全连接队列** ``` # echo 2000 > /proc/sys/net/core/somaxconn # echo 2000 > /proc/sys/net/core/somaxconn # echo 1500 > /proc/sys/net/core/somaxconn # echo 1500 > /proc/sys/net/core/somaxconn ``` **5. TCP SYN Queue和Accept Queue Overflow Explained** ``` # netstat -s | grep dropped     166 SYNs to LISTEN sockets dropped ```

正文

TCP建立连接的“三次握手”过程

上图就是tcp建联的三次握手过程。

  1. Server端需要先调用bind()方法,绑定ip和端口号,再调用listen()方法,然后就可以等待来自Client连接了
  2. Client 调用connect()后,就会发送SYN包到Server,此时Client端处理SYN_SENT状态
  3. Server收到SYN后,Server进入SYN_RCVD状态,回复SYN + ACK,此时该socket被放入半连接队列(SYN QUEUE)中。(这里要侧重说明一下,这里并不是说从Listen状态变成了SYN_RCVD,而是会生成一个新的(或者复用旧的)socket,新socket状态会变成SYN_RCVD状态,Server端的原来监听的socket状态还依然是LISTEN状态)
  4. Client 收到Server发回的ACK后,会再发送一次ACK到Server,Server收到ACK后三次连接建立,此时会把该socket从半连接队列中取出来放入全连接队列(ACCEPTED QUEUE)中,此时Client与Server端全部处理ESTABLISHED状态
  5. Server端调用accept()方法后,该连接会从全连接队列移出,交给应用层处理。

什么是“半连接队列(syn queue)" 和 "全连接队列(accept queue)"?

半连接队列:保存处于SYN_RCVD状态的socket的队列。

全连接队列:保存处于ESTABLISHED状态的socket的队列。(已经完成三次握手,Server还未调用accept()函数将socket交由应用层处理)

全连接队列(accept queue)

全连接对列最大长度计算公式:

min(net.core.somaxconn, backlog)

ps:

  • net.core.somaxconn为/proc/sys/net/core/somaxconn
  • backlog,listen(int sockfd, int backlog)函数传入的参数。比如:nginx中的listen指令的backlog参数。例如:'listen 80 backlog=1000;'

查看全连接队列长度

注意:连接状态不同,Recv-Q和Send-Q的含义不相同。

当连接在LISTEN状态下时,Recv-Q表示当前全连接队列的长度, Send-Q表示最大的全连接队列长度

# ss -lnt

State       Recv-Q Send-Q  Local Address:Port   Peer Address:Port

LISTEN      0         32768               *:9999              *:*  

LISTEN      0         100                 *:8080              *:*  

LISTEN      0         128                 *:18822             *:*  

LISTEN      0         50                  *:7879              *:*  

当连接在非LISTEN状态下时,Recv-Q表示已收到但未被应用进程读取的字节数;Send-Q表示的是已发送但未收到确认的字节数。

# ss -lnt | grep 80

State       Recv-Q Send-Q   Local Address:Port   Peer Address:Port

LISTEN     51        128          *:80                       *:*                 

LISTEN     0          128         :::80                      :::*                 

LISTEN     0          128         :::58803                   :::*                 

# ss -lnt | grep 80

LISTEN     129    128          *:80                       *:*                 

LISTEN     0      128         :::80                      :::*                 

LISTEN     0      128         :::58803                   :::*

查看全连接队列(accept queue)溢出的统计信息

# netstat -s | grep overflowed

    172308 times the listen queue of a socket overflowed

# netstat -s | grep overflowed

    175641 times the listen queue of a socket overflowed

注意:“172308 ,"175641 "是个累计值,常用后一次与前一次的取差值,若为正,则表示队列溢出。

全连接队列满了,怎么办?

当全连接队列满了,linux默认是丢弃连接,还可以通过/proc/sys/net/ipv4/tcp_abort_on_overflow值来控制。

若为0,则丢弃连接(默认)

若为1,则server 发送一个 reset 包给 client

如何调整全连接队列大小?

因为全连接队列大小=min(/proc/sys/net/core/somaxconn,backlog)。所以调整全连接队列大小时,两个都需要调。

比如:nginx默认backlog是511,linux 3.10.0内核/proc/sys/net/core/somaxconn 默认是128。

调整实例:

echo 2000 > /proc/sys/net/core/somaxconn

[root@rocketmq-server ipv4]# cat /etc/nginx/nginx.conf | grep listen

        listen       80 default_server backlog=1500;

[root@rocketmq-server ipv4]# ss -lnt | grep 80

LISTEN     0      1500         *:80                       *:* 

所以min(2000,1500)全连接队列变成了1500.

半连接队列

半连接队列最大长度计算公式

很多博客说SYN队列的最大长度是由/proc/sys/net/ipv4/tcp_max_syn_backlog参数指定的。实际上,只有当linux内核版本早于2.6.20时,SYN队列才等于backlog的大小。

实际上:SYN队列的最大长度由三个参数指定

  • 当你调用listen()时,传入的积压参数backlog
  • /proc/sys/net/core/somaxconn 的默认值为 128
  • /proc/sys/net/ipv4/tcp_max_syn_backlog 的默认值为 1024

查看当前半连接队列长度(只能粗略估计,SYN-RECV的数量少于实际半连接队列的长度)

#ss -antp | grep SYN-RECV | wc -l

查看半连接队列(syn queue)溢出的统计信息

# netstat -s | grep dropped

    166 SYNs to LISTEN sockets dropped

注意:“166”是个累计值,常用后一次与前一次的取差值,若为正,则表示队列溢出。

半连接队列满了,怎么办?

若半连接队列满了,根据不同情况,对连接可能有不同的处理方式,可能是直接丢弃,也可能是发送reset包

分如下几种情况:

  1. 如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
  2. 若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;
  3. 如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃;

"max_syn_backlog >> 2" :相当于右移2位,即max_syn_backlog / (2*2)

如何防御syn洪水攻击?

  • 增大半连接队列最大长度 (同时调大:/proc/sys/net/core/somaxconn,/proc/sys/net/ipv4/tcp_max_syn_backlog,listen(int sockfd, int backlog)中的backlog参数<每个服务都不一样>
  • 开启tcp_syncookies功能(echo 1 > /proc/sys/net/ipv4/tcp_syncookies )
  • 减少syn + ack重传次数(echo 1 > /proc/sys/net/ipv4/tcp_synack_retries )

参考文章:

4.4 TCP 半连接队列和全连接队列 | 小林coding

TCP SYN Queue and Accept Queue Overflow Explained - Alibaba Cloud Community

 

文章知识点与官方知识档案匹配,可进一步学习相关知识
CS入门技能树Linux入门初识Linux25458 人正在系统学习中

与[转帖]linux tcp 半连接队列和全连接队列相似的内容:

[转帖]linux tcp 半连接队列和全连接队列

TCP建立连接的“三次握手”过程 上图就是tcp建联的三次握手过程。 Server端需要先调用bind()方法,绑定ip和端口号,再调用listen()方法,然后就可以等待来自Client连接了Client 调用connect()后,就会发送SYN包到Server,此时Client端处理SYN_SE

[转帖]TCP的blacklog之全连接队列与半连接队列的深入研究

文章目录 Linux内核探测工具systemtap的安装与使用backlog、半连接队列、全连接队列是什么半连接队列、全连接队列基本概念 linux 内核是如何计算半连接队列、全连接队列的半连接队列的大小的计算模拟半连接队列占满全连接队列(Accept Queue) SYN+ACK重传次数全连接队列

[转帖]Linux内核 TCP/IP、Socket参数调优

文章系转载,便于整理和分类,原文地址:http://www.360doc.com/content/14/0606/16/3300331_384326124.shtml Doc1: /proc/sys/net目录 所有的TCP/IP参数都位于/proc/sys/net目录下(请注意,对/proc/sy

[转帖]Linux 系统TCP连接内存大小限制 调优

https://www.cnblogs.com/liujunjun/p/12496677.html 系统TCP连接内存大小限制 TCP的每一个连接请求,读写都需要占用系统内存资源,可根据系统配置,对TCP连接数,内存大小,限制调优。 查看系统内存资源 记录内存 详情:cat /proc/meminf

[转帖]linux 统计 TCP 网络连接状态

https://www.cnblogs.com/leffss/p/15471501.html 两种方法: awk 统计 $ ss -a|grep '^tcp'|awk '{ ++State[$2] } END { for (i in State) print i,State[i] }' LISTEN

[转帖]linux 内核协议栈 TCP time_wait 原理、配置、副作用

https://my.oschina.net/u/4087916/blog/3051356 0. 手把手教你做中间件、高性能服务器、分布式存储技术交流群 手把手教你做中间件、高性能服务器、分布式存储等 (redis、memcache、nginx、大容量 redis pika、rocksdb、mong

[转帖]linux查看端口及端口详解

https://www.cnblogs.com/the-tops/p/6126941.html 今天现场查看了TCP端口的占用情况,如下图 红色部分是IP,现场那边问我是不是我的程序占用了tcp的链接,,我远程登陆现场查看了一下,这种类型的tcp链接占用了400多个,,后边查了一下资料,说ESTAB

[转帖]Linux探测工具BCC(网络)

https://www.cnblogs.com/charlieroro/p/13273179.html 目录 Linux探测工具BCC(网络) Icmp的探测 TCP的探测 Icmp的探测 首先看下促使我学习bcc的这篇文章中的程序traceicmpsoftirq.py,使用该程序的本意是找出对pi

[转帖]Linux conntrack模块,ip_conntrack 模块的作用

ip_conntrack 是Linux NAT一个跟踪连接条目的模块记录着允许的跟踪连接条目ip_conntrack 模块会记录 tcp 通讯协议的 established connection 记录, 而且预设 timeout 时间长达五天 (432,000 秒).所以局域网中当有人使用p2p类的

[转帖]Linux内核参数net.ipv4.ip_local_port_range对服务器连接数影响的正确解释

首先明确一下该参数的意义:net.ipv4.ip_local_port_range表示本机作为客户端对外发起tcp/udp连接时所能使用的临时端口范围。 对于TCP连接,本机所能发起的tcp连接数受四元组(源地址*源端口*目标地址*目标端口)限制。 而对于UDP连接,本机所能发起的udp连接数则受二