0

0

Linux TCP 三次握手在内核中发生了什么?

冷漠man

冷漠man

发布时间:2026-01-23 20:33:23

|

800人浏览过

|

来源于php中文网

原创

三次握手内核状态流转为TCP_LISTEN→TCP_SYN_RECV→TCP_ESTABLISHED:SYN触发tcp_conn_request()生成request_sock入半连接队列,仅ACK到达才分配完整socket并移入established队列。

linux tcp 三次握手在内核中发生了什么?

三次握手的内核状态机怎么流转

Linux 内核用 sk_state 字段维护 socket 的连接状态,三次握手全程不经过用户态,全在协议里完成。关键状态是 TCP_LISTENTCP_SYN_RECVTCP_ESTABLISHED,但中间有隐藏细节:

  • TCP_LISTEN 状态下,内核把新 SYN 包交给 tcp_conn_request() 处理,不是直接创建新 socket,而是先查 reqsk_queue(半连接队列)是否能容纳
  • 收到 SYN 后,内核生成一个 request_sock 对象,存进半连接队列,此时还没分配 struct sock;只有收到第三次 ACK 才真正分配完整 socket 并移到 established 队列
  • 如果半连接队列满(由 net.ipv4.tcp_max_syn_backlog 控制),且未启用 syncookies,内核直接丢弃 SYN,不会回 SYN+ACK

syncookies 是怎么绕过半连接队列的

syncookies 不是“开关”,而是一种状态压缩机制:当半连接队列溢出时,内核放弃保存 request_sock,转而把客户端 IP、端口、时间戳、MSS 等信息编码进初始序列号(ISN)中。下次收到 ACK 时,再从 ACK 的确认号里反解出这些信息,验证合法性。

  • 启用条件:必须同时满足 net.ipv4.tcp_syncookies = 1 且半连接队列满(或 net.ipv4.tcp_synack_retries = 0
  • 代价:无法支持 TCP 选项如 SACK、Timestamps(除非开启 net.ipv4.tcp_timestamps = 1 且内核 ≥ 4.4)
  • 注意:tcp_syncookiesnet.ipv4.conf.all.rp_filter = 1 且反向路径校验失败时可能被静默禁用

accept() 系统调用到底在等什么

accept() 不参与三次握手,它只从内核的 established 队列(全连接队列)里取已处于 TCP_ESTABLISHED 状态的 socket。这个队列长度由 listen()backlog 参数和 net.core.somaxconn 共同决定,取二者最小值。

Baklib
Baklib

在线创建产品手册、知识库、帮助文档

下载
  • 如果全连接队列满,新完成握手的连接会被丢弃(不发 RST),表现为客户端卡在 TCP_SYN_SENT 或超时重传
  • ss -lnt 输出里的 Recv-Q 列显示当前全连接队列积压数,Send-Q 是最大长度
  • 应用层看到 EAGAIN/EWOULDBLOCK 通常不是因为队列满,而是 socket 设为非阻塞后 accept() 暂无就绪连接

TIME_WAIT 和连接复用对握手的影响

客户端主动关闭后进入 TIME_WAIT 状态(持续 2MSL),主要防止延迟到达的旧包干扰新连接。但它不影响新连接的三次握手——只要源端口不同,或目标四元组(src_ip:src_port + dst_ip:dst_port)不完全相同,就能立即建新连接。

  • 复用 TIME_WAIT socket 需显式设置 SO_REUSEADDR(服务端常用),但客户端通常不需要;SO_LINGER 设为 0 强制跳过 TIME_WAIT 有风险,可能丢包
  • 短连接服务若频繁遇到 Cannot assign requested address,大概率是本地端口耗尽,需调大 net.ipv4.ip_local_port_range 或启用端口复用
  • 内核不会因为存在 TIME_WAIT 就拒绝 SYN;真正拦截 SYN 的,通常是防火墙规则、连接跟踪表满(nf_conntrack)、或 SYN flood 防御触发

真正容易被忽略的是半连接队列和全连接队列的独立性——它们由不同参数控制,溢出表现也不同;还有 syncookies 的启用逻辑依赖运行时条件,不是写个 sysctl 就万事大吉。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

393

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

574

2023.08.10

磁盘配额是什么
磁盘配额是什么

磁盘配额是计算机中指定磁盘的储存限制,就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。php中文网为大家提供各种磁盘配额相关的内容,教程,供大家免费下载安装。

1352

2023.06.21

如何安装LINUX
如何安装LINUX

本站专题提供如何安装LINUX的相关教程文章,还有相关的下载、课程,大家可以免费体验。

704

2023.06.29

linux find
linux find

find是linux命令,它将档案系统内符合 expression 的档案列出来。可以指要档案的名称、类别、时间、大小、权限等不同资讯的组合,只有完全相符的才会被列出来。find根据下列规则判断 path 和 expression,在命令列上第一个 - ( ) , ! 之前的部分为 path,之后的是 expression。还有指DOS 命令 find,Excel 函数 find等。本站专题提供linux find相关教程文章,还有相关

294

2023.06.30

linux修改文件名
linux修改文件名

本专题为大家提供linux修改文件名相关的文章,这些文章可以帮助用户快速轻松地完成文件名的修改工作,大家可以免费体验。

777

2023.07.05

linux系统安装教程
linux系统安装教程

linux系统是一种可以免费使用,自由传播,多用户、多任务、多线程、多CPU的操作系统。本专题提供linux系统安装教程相关的文章,大家可以免费体验。

573

2023.07.06

linux查看文件夹大小
linux查看文件夹大小

Linux是一种自由和开放源码的类Unix操作系统,存在着许多不同的Linux版本,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,比如手机、平板电脑、路由器、视频游戏控制台、台式计算机、大型机和超级计算机。linux怎么查看文件夹大小呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

547

2023.07.20

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.7万人学习

Git 教程
Git 教程

共21课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号