首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
TCP三次握手和四次挥手的全过程
📅 2026/9/17 12:27:42
✍️ 爱科研究院
👁 阅读 3,247
三次握手和四次挥手是各个公司常见的考点也具有一定的水平区分度,希望大家能带着如下问题进行阅读收获会更大:请画出三次握手和四次挥手的示意图为什么连接的时候是三次握手什么是半连接队列ISN(Initial Sequence Number)是固定的吗三次握手过程中可以携带数据吗如果第三次握手丢失了客户端服务端会如何处理SYN攻击是什么挥手为什么需要四次四次挥手释放连接时等待2MSL的意义?TCP三次握手和四次挥手的全过程TCP是主机对主机层的传输控制协议提供可靠的连接服务采用三次握手确认建立一个连接: 位码即tcp标志位,有6种表示:SYN(synchronous建立连接)ACK(acknowledgement 表示响应、确认)PSH(push表示有DATA数据传输)FIN(finish关闭连接)RST(reset表示连接重置)URG(urgent紧急指针字段值有效)三次握手三次握手Three-way Handshake其实就是指建立一个TCP连接时需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口建立TCP连接并同步连接双方的序列号和确认号交换TCP窗口大小信息.刚开始客户端处于 Closed 的状态服务端处于 Listen 状态,进行三次握手:第一次握手(我想连你我的起始序号是 x):客户端给服务端发一个 SYN 报文并指明客户端的初始化序列号x,此时客户端处于 SYN_SEND 状态。首部的同步位SYN1初始序号seqxSYN1的报文段不能携带数据但要消耗掉一个序号。第二次握手(我同意我的起始序号是 y已收到你的 SYN):服务器收到客户端的 SYN 报文之后会以自己的 SYN 报文作为应答并且也是指定了自己的初始化序列号y。同时会把客户端的 x 1 作为ACK 的值表示自己已经收到了客户端的 SYN此时服务器处于 SYN_REVD 的状态。在确认报文段中SYN1ACK1确认号ackx1初始序号seqy。第三次握手(确认收到你的 SYNACK连接建立):客户端收到 SYN 报文之后会发送一个 ACK 报文当然也是一样把服务器的 y 1 作为 ACK 的值表示已经收到了服务端的 SYN 报文此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后也处于 ESTABLISHED 状态此时双方已建立起了连接。确认报文段ACK1确认号acky1序号seqx1初始为seqx第二个报文段所以要1ACK报文段可以携带数据不携带数据则不消耗序号。发送第一个SYN的一端将执行主动打开active open接收这个SYN并发回下一个SYN的另一端执行被动打开passive open。在socket编程中客户端执行connect()时将触发三次握手握手过程中传送的包里不包含数据三次握手完毕后客户端与服务器才正式开始传送数据。理想状态下TCP连接一旦建立在通信双方中的任何一方主动关闭连接之前TCP 连接都将被一直保持下去。确认号其数值等于发送方的发送序号1(即接收方期望接收的下一个序列号)。状态含义CLOSED客户端初始状态表示当前没有连接LISTEN服务端处于监听状态等待客户端的连接请求SYN_SENT客户端已发送SYN报文等待服务端确认SYN_RCVD服务端已收到SYN并发送了SYNACK等待客户端确认ESTABLISHED连接已建立双方可以开始传输数据控制标志位FlagsSYNSynchronize作用用于发起连接同步序列号握手过程中只有在第一次和第二次报文时SYN1表示这是一个连接请求/响应报文第三次握手时SYN0图中未标出因为连接已确认不再需要同步ACKAcknowledgment作用确认号是否有效ACK1表示报文中的ack字段有效即对收到数据的确认第一次握手时没有ACKACK0第二、三次握手ACK1序号与确认号seqSequence Number序列号表示本报文段所发送数据的第一个字节的序号每次发送数据时seq 会累加发送的字节数SYN 和 FIN 报文各占用一个序号ackAcknowledgment Number确认号表示期望收到对方下一个报文段的第一个字节的序号计算公式ack 对方发送的 seq 1当SYN1时只有当ACK1时ack 字段才有意义三次握手逐条解析第一次握手客户端 → 服务端SYN1, seqx客户端随机生成初始序列号x向服务端发起连接请求客户端进入SYN_SENT状态第二次握手服务端 → 客户端SYN1, ACK1, seqy, ackx1服务端也随机生成自己的初始序列号yackx1表示我收到了你的 seqx期待你下次发 seqx1服务端进入SYN_RCVD状态第三次握手客户端 → 服务端ACK1, seqx1, acky1客户端确认服务端的 SYNacky1表示我收到了你的 seqy期待你下次发 seqy1客户端的seqx1是因为第一次握手的 SYN 占用了序号 x双方进入ESTABLISHED状态开始数据传送为什么需要三次握手次数目的第一次客户端告诉服务端我能发送你能接收吗第二次服务端告诉客户端我能接收也能发送你能接收吗第三次客户端告诉服务端我能接收连接确认四次挥手建立一个连接需要三次握手而终止一个连接要经过四次挥手也有将四次挥手叫做四次握手的。这由TCP的半关闭half-close造成的。所谓的半关闭其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。TCP 的连接的拆除需要发送四个包因此称为四次挥手(Four-way handshake)客户端或服务器均可主动发起挥手动作。 刚开始双方都处于 ESTABLISHED 状态假如是客户端先发起关闭请求。四次挥手的过程如下第一次挥手(我发完了准备关闭):客户端发送一个 FIN 报文报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。即发出连接释放报文段FIN1序号sequ并停止再发送数据主动关闭TCP连接进入FIN_WAIT1终止等待1状态等待服务端的确认。第二次挥手(收到你的 FIN但我可能还有数据要发):服务端收到 FIN 之后会发送 ACK 报文且把客户端的序列号值 1 作为 ACK 报文的序列号值表明已经收到客户端的报文了此时服务端处于 CLOSE_WAIT 状态。 即服务端收到连接释放报文段后即发出确认报文段ACK1确认号acku1序号seqv服务端进入CLOSE_WAIT关闭等待状态此时的TCP处于半关闭状态客户端到服务端的连接释放。客户端收到服务端的确认后进入FIN_WAIT2终止等待2状态等待服务端发出的连接释放报文段。第三次挥手(我也发完了可以关了):如果服务端也想断开连接了和客户端的第一次挥手一样发给 FIN 报文且指定一个序列号。此时服务端处于 LAST_ACK 的状态。 即服务端没有要向客户端发出的数据服务端发出连接释放报文段FIN1ACK1序号seqw确认号acku1服务端进入LAST_ACK最后确认状态等待客户端的确认。第四次挥手(确认你关了我等一会儿再彻底关闭):客户端收到 FIN 之后一样发送一个 ACK 报文作为应答且把服务端的序列号值 1 作为自己 ACK 报文的序列号值此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态服务端收到 ACK 报文之后就处于关闭连接了处于 CLOSED 状态。客户端收到服务端的连接释放报文段后对此发出确认报文段ACK1sequ1ackw1客户端进入TIME_WAIT时间等待状态。此时TCP未释放掉需要经过时间等待计时器设置的时间2MSL后客户端才进入CLOSED状态。收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的服务端通常执行被动关闭不会进入TIME_WAIT状态。在socket编程中任何一方执行close()操作即可产生挥手操作。TCP的三次握手过程为什么会采用三次握手若采用二次握手可以吗弄清这个问题我们需要先弄明白三次握手的目的是什么能不能只用两次握手来达到同样的目的。第一次握手客户端发送网络包服务端收到了。这样服务端就能得出结论客户端的发送能力、服务端的接收能力是正常的。第二次握手服务端发包客户端收到了。这样客户端就能得出结论服务端的接收、发送能力客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。第三次握手客户端发包服务端收到了。这样服务端就能得出结论客户端的接收、发送能力正常服务器自己的发送、接收能力也正常。因此需要三次握手才能确认双方的接收与发送能力是否正常。试想如果是用两次握手则会出现下面这种情况如客户端发出连接请求但因连接请求报文丢失而未收到确认于是客户端再重传一次连接请求。后来收到了确认建立了连接。数据传输完毕后就释放了连接客户端共发出了两个连接请求报文段其中第一个丢失第二个到达了服务端但是第一个丢失的报文段只是在某些网络结点长时间滞留了延误到连接释放以后的某个时间才到达服务端此时服务端误认为客户端又发出一次新的连接请求于是就向客户端发出确认报文段同意建立连接不采用三次握手只要服务端发出确认就建立新的连接了此时客户端忽略服务端发来的确认也不发送数据则服务端一致等待客户端发送数据浪费资源。什么是半连接队列服务器第一次收到客户端的 SYN 之后就会处于 SYN_RCVD 状态此时双方还没有完全建立其连接服务器会把此种状态下请求连接放在一个队列里我们把这种队列称之为半连接队列。当然还有一个全连接队列就是已经完成三次握手建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。这里在补充一点关于SYN-ACK 重传次数的问题服务器发送完SYN-ACK包如果未收到客户确认包服务器进行首次重传等待一段时间仍未收到客户确认包进行第二次重传。如果重传次数超过系统规定的最大重传次数系统将该连接信息从半连接队列中删除。注意每次重传等待的时间不一定相同一般会是指数增长例如间隔时间为 1s2s4s8s…ISN(Initial Sequence Number)是固定的吗当一端为建立连接而发送它的SYN时它为连接选择一个初始序号。ISN随时间而变化因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送而导致某个连接的一方对它做错误的解释。三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number)以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的攻击者很容易猜出后续的确认号因此 ISN 是动态生成的。三次握手过程中可以携带数据吗其实第三次握手的时候是可以携带数据的。但是第一次、第二次握手不可以携带数据为什么这样呢?大家可以想一个问题假如第一次握手可以携带数据的话如果有人要恶意攻击服务器那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常然后疯狂着重复发 SYN 报文的话这会让服务器花费很多时间、内存空间来接收这些报文。也就是说第一次握手不可以放数据其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话此时客户端已经处于 ESTABLISHED 状态。对于客户端来说他已经建立起连接了并且也已经知道服务器的接收、发送能力是正常的了所以能携带数据也没啥毛病。SYN攻击是什么攻击原理发送大量 SYN 不完成第三次握手耗尽服务端半连接队列服务器端的资源分配是在二次握手时分配的而客户端的资源是在完成三次握手时分配的所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址并向Server不断地发送SYN包Server则回复确认包并等待Client确认由于源地址不存在因此Server需要不断重发直至超时这些伪造的SYN包将长时间占用未连接队列导致正常的SYN请求因为队列满而被丢弃从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。检测 SYN 攻击非常的方便当你在服务器上看到大量的半连接状态时特别是源IP地址是随机的基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。netstat -n -p TCP | grep SYN_RECV常见的防御 SYN 攻击的方法有如下几种缩短超时SYN Timeout时间增加最大半连接数(somaxconn)过滤网关防护(防火墙限速)SYN cookies技术挥手为什么需要四次因为当服务端收到客户端的SYN连接请求报文后可以直接发送SYNACK报文。其中ACK报文是用来应答的SYN报文是用来同步的。但是关闭连接时当服务端收到FIN报文时很可能并不会立即关闭SOCKET所以只能先回复一个ACK报文告诉客户端“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了我才能发送FIN报文因此不能一起发送。故需要四次挥手。全双工关闭TCP 支持两个方向独立关闭确保所有数据都已传输完毕避免旧连接的报文干扰新连接为什么 ISN初始序列号要随机防止旧连接的延迟报文被新连接误认为有效数据2MSL等待状态TIME_WAIT状态也成为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSLMaximum Segment Lifetime它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的因为TCP报文段以IP数据报在网络内传输而IP数据报则有限制其生存时间的TTL字段。对一个具体实现所给定的MSL值处理的原则是当TCP执行一个主动关闭并发回最后一个ACK该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失另一端超时并重发最后的FIN。这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间定义这个连接的插口客户的IP地址和端口号服务器的IP地址和端口号不能再被使用。这个连接只能在2MSL结束后才能再被使用。四次挥手释放连接时等待2MSL的意义?MSL是Maximum Segment Lifetime的英文缩写可译为“最长报文段寿命”它是任何报文在网络上存在的最长时间超过这个时间报文将被丢弃。为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK接着客户端再重传一次确认重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL而是在发送完ACK之后直接释放关闭一但这个ACK丢失的话服务器就无法正常的进入关闭连接状态。两个理由保证客户端发送的最后一个ACK报文段能够到达服务端。这个ACK报文段有可能丢失使得处于LAST-ACK状态的B收不到对已发送的FINACK报文段的确认服务端超时重传FINACK报文段而客户端能在2MSL时间内收到这个重传的FINACK报文段接着客户端重传一次确认重新启动2MSL计时器最后客户端和服务端都进入到CLOSED状态若客户端在TIME-WAIT状态不等待一段时间而是发送完ACK报文段后立即释放连接则无法收到服务端重传的FINACK报文段所以不会再发送一次确认报文段则服务端无法正常进入到CLOSED状态。防止“已失效的连接请求报文段”出现在本连接中。客户端在发送完最后一个ACK报文段后再经过2MSL就可以使本连接持续的时间内所产生的所有报文段都从网络中消失使下一个新的连接中不会出现这种旧的连接请求报文段。为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态理论上四个报文都发送完毕就可以直接进入CLOSE状态了但是可能网络是不可靠的有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。大量 TIME_WAIT 有什么影响如何优化影响占用端口资源可能导致客户端端口耗尽优化启用tcp_tw_reuse谨慎使用调整net.ipv4.tcp_fin_timeout服务端主动关闭连接减少客户端 TIME_WAIT参考: https://zhuanlan.zhihu.com/p/86426969
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/9/17 12:22:41
Harmony鸿蒙实战开发-个人记事本app「密码登录保护-简洁版」【源码在文末】
2026/9/17 12:22:41
background-agents Managed Skills教程:5分钟创建可复用Agent指令集的完整指南
2026/9/17 12:22:41
python毕业设计项目选题基于django的大数据技术的农产品电商平台设计与实现
2026/9/17 17:38:55
MATLAB连续时间信号卷积实现:Ts缩放与时轴重建的避坑指南
2026/9/17 17:38:55
同一把 TaoToken Key,从 Gemini 3.8 Live 切到 3.8 Live Extended Thinking
2026/9/17 17:38:55
Rerun Lenses 实战指南:在 Rust 中转换、过滤与重塑数据流
2026/9/17 17:38:55
Zcash v1.0.8-1 补丁版解析:JoinSplit 交易优先级与内存池崩溃漏洞修复
2026/9/17 17:38:55
Matlab实现Retinex图像增强:SSR/MSR/MSRCR/MSRCP对比分析
2026/9/17 17:33:55
Markdown本质:一种面向机器的纯文本内容契约
2026/9/17 0:00:44
开学论文写作指南:核心框架梳理与高效完成技巧分享
2026/9/17 0:00:44
OpenMAIC:轻量级多Agent教学框架实战指南
2026/9/17 0:00:44
AWS无服务器应用开发指南:从Lambda到SAM的架构与实践
2026/9/16 18:36:59
拯救者Y7000黑屏故障排查与维修实战指南
2026/9/16 7:38:03
AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
2026/9/17 4:19:54
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化