【tcp】TCP 半连接队列、全连接队列基本概念

本文深入解析TCP三次握手的过程,包括客户端和服务端的状态变化,并详细解释了半连接队列与全连接队列的作用及其实现机制。

TCP  三次握手状态变化

对于客户端:

初始的状态是处于 CLOSED 状态。CLOSED 并不是一个真实的状态,而是一个假想的起点和终点。

客户端调用 connect 以后会发送 SYN 同步报文给服务端,然后进入 SYN-SENT 阶段,客户端将保持这个阶段直到它收到了服务端的确认包。

如果在 SYN-SENT 状态收到了服务端的确认包,它将发送确认服务端 SYN 报文的 ACK 包,同时进入 ESTABLISHED 状态,表明自己已经准备好发送数据。

对于服务端:

初始状态同样是 CLOSED 状态。

在执行 bind、listen 调用以后进入 LISTEN状态,等待客户端连接。

当收到客户端的 SYN 同步报文以后,会回复确认同时发送自己的 SYN 同步报文,这时服务端进入 SYN-RCVD 阶段等待客户端的确认。

当收到客户端的确认报文以后,进入ESTABLISHED 状态。这时双方可以互相发数据了。

当服务端调用 listen 函数时,TCP 的状态被从 CLOSE 状态变为 LISTEN,于此同时内核创建了两个队列:

半连接队列(Incomplete connection queue),又称 SYN 队列

全连接队列(Completed connection queue),又称 Accept 队列

半连接队列

当客户端发起 SYN 到服务端,服务端收到以后会回 ACK 和自己的 SYN。这时服务端这边的 TCP 从 listen 状态变为 SYN_RCVD (SYN Received),此时会将这个连接信息放入「半连接队列」,半连接队列也被称为 SYN Queue,存储的是 “inbound SYN packets”。

服务端回复 SYN+ACK 包以后等待客户端回复 ACK,同时开启一个定时器,如果超时还未收到 ACK 会进行 SYN+ACK 的重传,重传的次数由 tcp_synack_retries 值确定。

在 CentOS 上这个值等于 5。

一旦收到客户端的 ACK,服务端就开始尝试把它加入另外一个全连接队列(Accept Queue)。

全连接队列

「全连接队列」包含了服务端所有完成了三次握手,但是还未被应用调用 accept 取走的连接队列。

此时的 socket 处于 ESTABLISHED 状态。每次应用调用 accept() 函数会移除队列头的连接。如果队列为空,accept() 通常会阻塞。全连接队列也被称为 Accept 队列

你可以把这个过程想象生产者、消费者模型:

内核是一个负责三次握手的生产者,握手完的连接会放入一个队列。

我们的应用程序是一个消费者,取走队列中的连接进行下一步的处理。

这种生产者消费者的模式,在生产过快、消费过慢的情况下就会出现队列积压。

listen 函数的第二个参数 backlog 用来设置全连接队列大小,但不一定就会选用这一个 backlog 值,还受限于 somaxconn,等下会有更详细的内容说明全连接队列大小的计算规则。

int listen(int sockfd, int backlog)

如果全连接队列满,内核会舍弃掉 client 发过来的 ack(应用层会认为此时连接还未完全建立)。

ss 命令可以查看全连接队列的大小和当前等待 accept 的连接个数,执行 ss -lnt 即可。

对于 LISTEN 状态的套接字,Recv-Q 表示 accept 队列排队的连接个数Send-Q 表示全连接队列(也就是 accept 队列)的总大小。

套接字信息

ifconfig 和 ip 只显示了网络接口收发数据包的统计信息,但在实际的性能问题中,网络协议栈中的统计信息,我们也必须关注。你可以用 netstat 或者 ss ,来查看套接字、网络栈、网络接口以及路由表的信息。

我个人更推荐,使用 ss 来查询网络的连接信息,因为它比 netstat 提供了更好的性能(速度更快)。

比如,你可以执行下面的命令,查询套接字信息:

netstat 和 ss 的输出也是类似的,都展示了套接字的状态、接收队列、发送队列、本地地址、远端地址、进程 PID 和进程名称等。

其中,接收队列(Recv-Q)和发送队列(Send-Q)需要你特别关注,它们通常应该是 0。

当你发现它们不是 0 时,说明有网络包的堆积发生。

当然还要注意,在不同套接字状态下,它们的含义不同:

syn backlog 是 TCP 协议栈中的半连接队列(sync queue)长度,相应的也有一个全连接队列(accept queue),它们都是维护 TCP 状态的重要机制。

顾名思义,所谓半连接,就是还没有完成 TCP 三次握手的连接,连接只进行了一半,而服务器收到了客户端的 SYN 包后,就会把这个连接放到半连接队列中,然后再向客户端发送 SYN+ACK 包。而全连接,则是指服务器收到了客户端的 ACK,完成了 TCP 三次握手,然后就会把这个连接挪到全连接队列中。这些全连接中的套接字,还需要再被 accept() 系统调用取走,这样,服务器就可以开始真正处理客户端的请求了。 

参考

TCP 三次握手原理,你真的理解吗?

https://mp.weixin.qq.com/s/yH3PzGEFopbpA-jw4MythQ

TCP SOCKET中backlog参数的用途是什么?

http://www.cnxct.com/something-about-phpfpm-s-backlog/

<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]: 关于MSS和MTU的内容。 - 引用[5]: 关于epoll和accept系统调用。 用户的问题核心是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、付费专栏及课程。

余额充值