c++ tcp的三次握手

TCP 三次握手(一次性讲透,面试版,结合工控Qt网络场景)

一句话本质

TCP 是可靠的、面向连接的协议。三次握手核心目的:双向确认收发能力,协商初始序列号ISN,建立连接。

简单大白话:

客户端 ↔ 服务端,要互相确认两件事:我能发消息给你,我也能收到你的消息。

一次握手只能单向验证,需要来回3次报文,完成双向确认。

角色约定:

• 客户端(Client):主动发起连接(比如你的Qt程序去连接工控设备服务端)

• 服务端(Server):监听端口,等待连接

📩三步完整流程

第1次握手:客户端 → 服务端 【SYN】

客户端:SYN报文,携带客户端初始序列号 ISN(c)

含义:客户端说:我想和你建立连接,我的消息编号从 ISN(c) 开始

客户端状态:CLOSED → SYN_SENT

服务端收到后状态:LISTEN → SYN_RCVD

SYN(Synchronize):同步序列号标志位

第2次握手:服务端 → 客户端 【SYN + ACK】

服务端回复一个报文同时带两个标记

  1. SYN:服务端自己的初始序列号 ISN(s)

  2. ACK:确认客户端的SYN,确认号 = ISN(c)+1

含义:服务端说:收到你的请求了!我这边也准备好,我的编号从ISN(s)开始;我确认收到了你第ISN(c)号包

✅到这里:服务端确认两件事:客户端能发消息给我、我能收到客户端消息

但是!客户端还不知道:服务端能不能收到我发的ACK,连接还不能建立。

第3次握手:客户端 → 服务端 【ACK】

客户端发送ACK报文,确认号 = ISN(s)+1

含义:客户端说:收到你的SYN消息,确认你的序列号。

✅收到这个ACK之后:

服务端:SYN_RCVD → ESTABLISHED(连接成功)

客户端收到服务端的SYN+ACK之后就已经进入 ESTABLISHED,发送完第三次ACK,连接双向就绪,可以收发业务数据。

👉重点:第三次ACK报文可以携带业务数据(部分操作系统支持),但是一般不会放;SYN报文不能携带数据

✅核心结论:为什么是3次,不是2次?(面试必考题)

假设只握手2次:

客户端发SYN → 服务端回复SYN+ACK,服务端单方面认为连接建立,直接准备资源。

会有经典的失效SYN报文问题:

网络延迟的旧连接请求,到达服务端,两次握手后服务端建立连接、分配内存;但是客户端早就放弃这个连接了,不会发数据。服务端白白占用端口和内存资源,造成资源浪费。

三次握手,必须客户端最后发ACK确认,服务端收到ACK才正式完成连接,规避这个问题。

一句话记:两次握手,服务端无法确认「客户端能不能收到我的消息」。

序列号 ISN 是干嘛的?

TCP是字节流,每个字节都有序列号:

  1. 用来排序:网络乱序到达的数据包,接收端按序列号重组

  2. 去重:网络重复投递的包,用序列号识别丢弃

初始ISN不是固定0,是随机生成,防止网络嗅探、序列号预测攻击。

🧩和你Qt工控开发相关的实际理解

Qt QTcpSocket:

  1. socket->connectToHost() 底层就是发出第一次SYN;

  2. 服务端QTcpServer收到SYN,内核回复SYN+ACK(第二次握手);

  3. 客户端内核发出ACK(第三次握手);

  4. 三次握手全部完成后,Qt才会触发connected()信号。

注意:三次握手是操作系统内核TCP协议栈完成的,不是Qt应用层代码做的。你的Qt代码感知不到SYN报文,只能收到连接成功信号。

📌面试高频坑点

  1. Q:第三次握手丢包会怎么样?

A:服务端没收到ACK,不会进入ESTABLISHED,会超时重传【SYN+ACK】;如果多次重传失败,服务端释放资源。客户端这边已经认为连接建立了,后续发业务包,服务端会回复RST重置。

  1. Q:SYN、ACK是什么?

A:TCP头部的标志位,1表示开启。

• SYN=1:同步序列号,用于发起连接

• ACK=1:确认号有效,代表应答报文

  1. Q:三次握手可以传数据吗?

SY报文(1、2次握手)不允许携带数据;第三次握手ACK报文,协议允许携带业务数据,但是工程上一般不带。

配套对比:TCP四次挥手(顺带区分,面试经常一起问)

握手:建立连接,双向同步序列号,3次

挥手:断开连接,TCP是全双工,双方各自关闭发送通道,4次

极简记忆口诀

  1. 客:SYN,我要连你(1次)

  2. 服:SYN+ACK,收到!我也准备好(2次)

  3. 客:ACK,收到你的消息,连接就绪(3次)

相关推荐
syagain_zsx7 小时前
jsoncpp 使用指南:编译链接、Json::Value 取值与高频坑
c++·json·库·http格式
布莱克6058 小时前
理解 = delete 与 = default:两种赋值语义的差异
c++
小小、码农9 小时前
[特殊字符]【C++11】类的新功能全面解析:移动构造、移动赋值、default、delete、final 与 override
linux·开发语言·网络·c++
库玛西10 小时前
外部排序全解析:败者树、置换-选择排序与最佳归并树
c语言·数据结构·c++·笔记·考研·算法
General_G12 小时前
创建型模式—原型(Prototype)模式
c++·设计模式·原型模式
syagain_zsx12 小时前
protobuf 实战:从 .proto 到 C++ 序列化的完整链路
c++·学习·程序人生·谷歌·protobuf
welfare96212 小时前
新号别搞:C++_list
开发语言·c++
xiaoye-duck12 小时前
《C++ 项目:手写大模型接入 SDK》云端 API 调用基础与 Apifox 调试实战
网络·c++·语言模型
坤坤子吖12 小时前
Linux 线程同步与互斥——条件变量与线程同步
linux·开发语言·c++·笔记·学习
杜 硕13 小时前
从零开始的C++生活——第二讲——03
c++·生活