TCP握手中的半连接队列和全连接队列

本文详细解析了TCP连接管理中的重要概念backlog,包括其在半连接队列与全连接队列中的作用,以及如何影响客户端连接请求的处理。通过具体的Java代码示例,展示了不同场景下backlog对连接的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在之前学习TCP的三次握手时发现了一个比较重要的知识点,backlog。但是我没有遇到过。此篇权当是记录知识点以备后续。

流程图:


在握手阶段存在两个队列:syns queue(半连接队列);accept queue(全连接队列)

流程简述如下:

1. 客户端发送SYN付服务端进行第一次报文握手,此时服务端将此请求信息放在半连接队列中并回复SYN+ACK给客户端。

此处就是SYN Flood(后续关注,此篇记录)攻击的点,攻击方要做的就是不停的建立连接,但是确不给出ACK确认,导致半连接队列满了,其他请求无法进入。

2. 客户端收到SYN+ACK,随机发出ACK确认给服务端;

    全队列未满:从半连接队列拿出此消息放入全队列中。

    全队列已满:处理方式和tcp_abort_on_overflow(cat /proc/sys/net/ipv4/tcp_abort_on_overflow)有关:

                      tcp_abort_on_overflow=0;表示丢弃该ACK;

                      tcp_abort_on_overflow=1;表示发送一个RST给客户端,直接废弃掉这个握手过程。

3. 服务端accept处理此请求,从全队列中将此请求信息拿出。

backlog:

backlog表明它是已连接但是还未处理的队列的大小。这个队列如果满的话,会发送一个ECONNREFUSED错误信息给客户端。就是常见的“Connection Refused”。

简单测试:使用Java内的socket测试:

客户端:

    private static Socket[] clients = new Socket[30];

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 10; i++) {
            clients[i] = new Socket("127.0.0.1", 8888);
            System.out.println("Client:" + i);
        }
    }

服务端1:

    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(8888, 5);

        while (true) {
            // server.accept();
        }
    }

输出:

Client:0
Client:1
Client:2
Client:3
Client:4
Exception in thread "main" java.net.ConnectException: Connection refused: connect
	at java.net.DualStackPlainSocketImpl.connect0(Native Method)
	at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)
	at java.net.Socket.connect(Socket.java:538)
	at java.net.Socket.<init>(Socket.java:434)
	at java.net.Socket.<init>(Socket.java:211)
	at Test1.main(Test1.java:15)

源码简析:从下面的源码内可以看见backlog提供了一个类似容量的限制,小于1或者不传默认值是50。因此在只提供了5个backlog大小的测试中,因为前5个占据了全连接队列没有被处理,第六个进来时,没有位置,所以拒绝了(从此处可以看见参数tcp_abort_on_overflow=1,0的话会直接丢弃)

    public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
        setImpl();
        if (port < 0 || port > 0xFFFF)
            throw new IllegalArgumentException(
                       "Port value out of range: " + port);
        if (backlog < 1)
          backlog = 50;
        try {
            bind(new InetSocketAddress(bindAddr, port), backlog);
        } catch(SecurityException e) {
            close();
            throw e;
        } catch(IOException e) {
            close();
            throw e;
        }
    }
服务端2:(注释打开)
    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(8888, 5);

        while (true) {
             server.accept();
        }
    }

输出:

Client:0
Client:1
Client:2
Client:3
Client:4
Client:5
Client:6
Client:7
Client:8
Client:9
此时由于accept处理的存在,使得全连接队列有位置,所以能够处理完所有的请求。

全连接队列的大小:

Java的Socket的默认backlog大小是50;(看上面源码分析)

Tomcat的默认backlog大小是100;(看8080端口)


可以自由配置

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="800" acceptCount="1000"/> 

AliTomcat默认backlog值为200;(参考别的连接)

Nginx的默认backlog值是511;

全队列的大小和backlog有关,但是未必是backlog的值,是由backlog和somaxconn(系统参数)两个值中的较小值决定。

cat /proc/sys/net/core/somaxconn

此处我贴一下linux下的大小是128,如果我们传进来的值是50,那么全队列大小就是50。

半连接队列的大小:

半连接的大小取决于64和tcp_max_syn_backlog的较大值。

cat /proc/sys/net/ipv4/tcp_max_syn_backlog 
本机的值是256。

通过ss查看Socket的状态:


基于上面的测试例子中的Java代码,这次backlo的值设置为10,作为明显区分。


Send-Q表示的就是当前端口的全连接队列大小,Recv-Q表示的是全连接队列使用的多少。


针对8888端口:客户端只循环了5次,所以Recv-Q的使用量只有5个,而全连接队列的大小是10。

先记录这么多,因为没有什么实际的问题作为继续研究的样例,所以没什么再深入的学习了。

贴一下参考博客:

阿里中间件

<think>首先,用户的问题是:“我想查询Linux系统中默认的TCP半连接队列长度 请问Linux default TCP half-open connection queue size”。这是一个关于Linux网络配置的问题。 回顾系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如[^1]。 用户可见层要求: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 参考站内引用: - 引用[1]: 关于tcp_conn_request函数处理TCP连接请求。 - 引用[2]: 描述了TCP栈的两个队列:半开连接队列(SYN队列接受队列。半开队列大小由/proc/sys/net/ipv4/tcp_max_syn_backlog指定,默认512,但前提是syncookies功能禁用。 - 引用[3]: 关于tcp_acceptq_queue函数如何将请求添加到队列。 - 引用[4]: 关于MSSMTU的内容。 - 引用[5]: 关于epollaccept系统调用。 用户的问题核心是Linux默认的TCP半连接队列长度。从引用[2]中,我得到了关键信息: - 半开连接队列(SYN队列)的大小由/proc/sys/net/ipv4/tcp_max_syn_backlog指定。 - 默认值是512,但仅当syncookies功能禁用时有效。如果syncookies启用,队列大小可能会不同。 我需要确认Linux的默认设置。在标准Linux系统中: - tcp_max_syn_backlog的默认值通常是512。 - syncookies功能默认是启用的(通过/proc/sys/net/ipv4/tcp_syncookies),如果设置为1或2。 在syncookies启用时,半连接队列的实际行为会改变。syncookies是一种安全机制,用于防止SYN洪水攻击。当syncookies启用时,内核不会为每个SYN请求分配内存,而是使用一个cookie机制,因此队列大小可能不是固定的。 因此,回答应该包括: - 默认配置:tcp_max_syn_backlog的默认值。 - syncookies的影响。 - 如何检查当前系统的设置。 结构清晰的回答: 1. 解释半连接队列是什么。 2. 给出默认大小。 3. 讨论syncookies的影响。 4. 提供如何查看修改设置的命令。 5. 添加引用标识。 生成相关问题: - 基于主题,生成2-3个相关问题。 用中文回答。 最终回答结构: - 开头直接回答问题。 - 逐步解释细节。 - 在相关部分添加引用。 - 结尾生成相关问题。 确认默认值: - 在大多数Linux发行版中,tcp_max_syn_backlog的默认值是512。 - tcp_syncookies默认值通常是1(启用)。 - 当syncookies启用时,半连接队列的实际大小可能不是tcp_max_syn_backlog的值,而是内核动态管理。 从引用[2]:"The default value is 512, but this setting is valid if the system's syncookies function is disabled." 所以,如果syncookies启用,队列大小可能无效或不同。 在Linux内核文档中,当syncookies启用时,半连接队列的大小限制被忽略,因为连接状态不存储在队列中。 因此,回答: - 默认tcp_max_syn_backlog是512。 - 但由于syncookies默认启用,实际半连接队列可能不固定。 - 建议用户检查系统设置。 添加命令示例: - 检查tcp_max_syn_backlog:`cat /proc/sys/net/ipv4/tcp_max_syn_backlog` - 检查tcp_syncookies:`cat /proc/sys/net/ipv4/tcp_syncookies` 生成相关问题: 1. 如何调整TCP半连接队列大小? 2. 什么是TCP syncookies,如何启用或禁用? 3. TCP半连接队列全连接队列的区别是什么?</think>### Linux系统中默认的TCP半连接队列长度 在Linux系统中,TCP半连接队列(也称为SYN队列)用于存储处于半开状态的TCP连接请求(即客户端发送了SYN包,但服务器还未完成三次握手)。这个队列的大小直接影响系统处理SYN洪水攻击的能力连接建立性能。以下是详细解答: #### 1. **默认队列长度** - Linux内核中,TCP半连接队列的默认大小由内核参数 `/proc/sys/net/ipv4/tcp_max_syn_backlog` 控制。 - **默认值为512**。这是在大多数Linux发行版(如Ubuntu、CentOS)的标准配置。 - 但是,这个默认值仅在系统的SYN cookies功能**禁用**时生效。如果SYN cookies启用,队列的实际行为会改变,队列大小可能不会被严格限制为512,而是由内核动态管理[^2]。 #### 2. **SYN cookies的影响** - SYN cookies是一种安全机制,用于防御SYN洪水攻击(恶意客户端发送大量SYN请求但不完成握手)。它默认是**启用**的,通过参数 `/proc/sys/net/ipv4/tcp_syncookies` 控制: - 如果 `tcp_syncookies = 1`(默认值),SYN cookies启用,半连接队列大小可能被忽略或动态调整,内核不会为每个SYN请求分配固定内存。 - 如果 `tcp_syncookies = 0`(禁用),半连接队列大小严格由 `tcp_max_syn_backlog` 定义(默认512)。 - 因此,在默认配置下(SYN cookies启用),半连接队列没有固定上限,而是依赖于内核的cookie机制[^2]。 #### 3. **如何检查当前系统设置** 您可以通过以下命令查看实际值: ```bash # 检查半连接队列大小参数 cat /proc/sys/net/ipv4/tcp_max_syn_backlog # 输出通常为 512 # 检查 SYN cookies 状态 cat /proc/sys/net/ipv4/tcp_syncookies # 输出 1 表示启用(默认),0 表示禁用 ``` - 如果需要修改默认值,可以临时设置(重启失效): ```bash sudo sysctl -w net.ipv4.tcp_max_syn_backlog=1024 ``` 或永久修改:在 `/etc/sysctl.conf` 中添加 `net.ipv4.tcp_max_syn_backlog=1024`,然后运行 `sudo sysctl -p`。 #### 4. **注意事项** - 半连接队列全连接队列(accept队列)不同:全连接队列大小由 `net.core.somaxconn` 应用程序的 `listen()` 函数的 `backlog` 参数共同决定[^2]。 - 在高并发场景下,如果队列过小,可能导致连接超时或丢弃。建议监控SYN丢包情况: ```bash netstat -s | grep "SYNs to LISTEN" ``` 如果输出显示大量丢包,可能需要调整 `tcp_max_syn_backlog` 或优化SYN cookies设置[^2][^5]。 总之,Linux默认TCP半连接队列长度为512,但受SYN cookies机制影响,实际行为可能动态变化。建议根据应用场景安全需求调整参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值