文章目录

目录

前言

一、TCP的三次握手,四次挥手

        1.三次握手(建立可靠连接)

      ​编辑  

2.四次挥手(终止可靠连接)

​编辑

3.为什么是三次和四次

        1.为什么是三次

        2.为什么是四次

补充:四次挥手中的2MSL

2MSL 核心定义与作用

二、TCP和UDP具体应用

1.TCP 与 UDP 核心特性对比(应用选择的关键)

2.具体应用场景

1. TCP 的典型应用(可靠优先)

2. UDP 的典型应用(实时性优先)

3.核心选择原则

三、TCP黏包问题如何确定边界

4 种高频边界确定方法

1. 固定长度法(最简单,局限性强)

2. 分隔符法(灵活,需避坑)

3. 长度字段法(最常用,通用性强)

4. 应用层协议封装法(标准化,适合复杂场景)

核心原则与面试总结



前言

        本文章主要解决TCP的常见面试问题


一、TCP的三次握手,四次挥手

        1.三次握手(建立可靠连接)

                核心目的:同步双方序列号 + 确认收发能力,确保连接可双向通信。

  1. 第一次握手(客户端→服务器):客户端发送 SYN 报文(同步序列编号),告知服务器 “我要连接,初始序号是 X”,客户端进入 SYN_SENT 状态。
  2. 第二次握手(服务器→客户端):服务器回应 SYN+ACK 报文,确认 “收到 X,我的初始序号是 Y”,服务器进入 SYN_RCVD 状态。
  3. 第三次握手(客户端→服务器):客户端发送 ACK 报文,确认 “收到 Y,连接可以建立”,双方进入 ESTABLISHED 状态(数据传输状态)。

        

2.四次挥手(终止可靠连接)

                核心目的:双方协商关闭连接,确保所有数据传输完成。

  1. 第一次挥手(主动关闭方→被动关闭方):主动方发送 FIN 报文(结束标志),告知 “我已无数据要发”,进入 FIN_WAIT_1 状态。
  2. 第二次挥手(被动关闭方→主动关闭方):被动方回应 ACK 报文,确认 “收到关闭请求”,进入 CLOSE_WAIT 状态(此时被动方仍可发送剩余数据)。
  3. 第三次挥手(被动关闭方→主动关闭方):被动方数据发送完毕后,发送 FIN 报文,告知 “我也无数据要发”,进入 LAST_ACK 状态。
  4. 第四次挥手(主动关闭方→被动关闭方):主动方回应 ACK 报文,确认 “收到关闭请求”,进入 TIME_WAIT 状态(等待 2MSL,确保被动方收到 ACK),双方最终进入 CLOSED 状态。

3.为什么是三次和四次

        1.为什么是三次

        两次握手无法确认客户端的接收能力(服务器无法判断自己的 SYN+ACK 是否被收到),三次才能确保双向通信链路通畅。

        2.为什么是四次

  1. 关闭连接时,被动方可能仍有数据未发送,需分 “确认关闭请求” 和 “自己发起关闭” 两步,无法像三次握手那样合并 SYN+ACK
  2. TIME_WAIT 作用:避免旧连接的残留报文干扰新连接,确保被动方收到最后一个 ACK。

补充:四次挥手中的2MSL

2MSL 核心定义与作用

        2MSL 是 Two Maximum Segment Lifetime 的缩写,即两倍的报文最大生存时间,是 TCP 协议中 TIME_WAIT 状态的等待时长标准。

  • MSL 定义:指 TCP 报文在网络中能存在的最长时间(避免报文因网络延迟、路由环路无限循环转发),典型值为 30 秒、1 分钟或 2 分钟(不同系统配置不同,常见 1 分钟)。
  • 2MSL 核心作用(面试必考点):
  1. 确保主动关闭方发送的最后一个 ACK 报文能被被动关闭方收到(若被动方没收到 FIN,会重发 FIN,2MSL 足够覆盖重发周期)。
  2. 等待网络中该连接的所有残留报文过期(防止旧报文干扰后续新建的同端口连接)。

简单说:2MSL 是 TCP 为了 “可靠关闭连接” “避免旧连接干扰” 设置的 “安全等待时间”TIME_WAIT 状态结束后,连接才会真正进入 CLOSED 状态。

二、TCP和UDP具体应用

1.TCP 与 UDP 核心特性对比(应用选择的关键)

特性 TCP(传输控制协议) UDP(用户数据报协议)
连接性 面向连接(三次握手建立,四次挥手关闭) 无连接(直接发送,无需建立连接)
可靠性 可靠(重传、流量控制、拥塞控制) 不可靠(无重传,可能丢失、乱序)
传输效率 较低(头部开销大,有确认 / 重传机制) 较高(头部仅 8 字节,无额外开销)
适用场景 需确保数据完整、有序的场景 实时性优先,可容忍少量数据丢失的场景

2.具体应用场景

1. TCP 的典型应用(可靠优先)
  • 网页浏览(HTTP/HTTPS):需完整接收 HTML、图片等数据,避免页面错乱,HTTPS 基于 TCP 实现加密传输。
  • 文件传输(FTP/SFTP):大文件传输需保证无丢失、无损坏,TCP 的重传机制可避免文件残缺。
  • 邮件发送(SMTP/POP3/IMAP):邮件内容、附件需准确送达,不允许丢失或乱序。
  • 远程登录(SSH/Telnet):远程操作设备需指令有序执行,TCP 确保指令传输可靠。
  • 数据库连接(MySQL/PostgreSQL):数据库查询、写入需原子性,TCP 避免数据传输错误导致事务异常。
  • 即时通讯(微信 / QQ 私聊文字):文字消息需准确送达,丢失会影响沟通,语音 / 视频则常用 UDP。
2. UDP 的典型应用(实时性优先)
  • 实时音视频(直播 / 视频通话 / 语音聊天):如抖音直播、Zoom 会议,低延迟比偶尔的数据包丢失更重要,丢失少量帧不影响整体体验。
  • 游戏联机(王者荣耀 / 英雄联盟):游戏操作指令需实时响应(如走位、放技能),UDP 的低延迟可避免操作卡顿,少量丢包可通过游戏算法补偿。
  • DNS 查询:域名解析请求小(仅几十字节),需快速响应,即使丢包也可重新发送,无需 TCP 的连接开销。
  • 流媒体传输(RTSP/RTP):视频点播、直播的音视频流,优先保证流畅播放,延迟过高会影响体验。
  • 物联网通信(MQTT 轻量化场景):传感器数据上报(如温度、湿度),数据量小、实时性要求高,可容忍偶尔丢包。

3.核心选择原则

  • 若数据 “不能丢、不能乱”(如文件、文字、数据库操作),选 TCP
  • “延迟要低、效率要高”(如音视频、游戏、实时数据),选 UDP,可通过应用层实现简单重传(如 RTP 协议封装音视频数据)。

三、TCP黏包问题如何确定边界

TCP 黏包的本质是 “流式协议无天然边界”,数据按字节流传输,接收方无法区分多个发送方的数据包。解决核心是 在应用层定义 “边界规则”,让接收方能够准确拆分黏包数据。

4 种高频边界确定方法

1. 固定长度法(最简单,局限性强)
  • 核心逻辑:约定每个数据包的固定字节数,接收方每次读取固定长度数据,即为一个完整包。
  • 实现方式:例如约定每个包 100 字节,发送方每次发送 100 字节数据,接收方循环读取 100 字节即可拆分。
  • 优缺点:优点是实现简单,无需额外解析;缺点是灵活性差,数据长度不固定时会浪费带宽(不足补 0)或截断数据。
  • 适用场景:数据长度固定的场景(如传感器固定格式上报数据)。
2. 分隔符法(灵活,需避坑)
  • 核心逻辑:约定特殊分隔符(如 \r\n、自定义字节序列 0xFFFF),接收方读取数据时,以分隔符作为包的结束标志。
  • 实现方式:发送方在每个数据包末尾添加分隔符(如 HTTP 协议的 \r\n\r\n 分隔请求头和正文);接收方缓冲区累积数据,直到匹配到分隔符,拆分出完整包。
  • 关键避坑:需确保数据本身不包含分隔符(否则会误拆分),解决方案是 “转义处理”(如数据中的 \r\n 转义为 \r\n\0)。
  • 优缺点:优点是灵活,无需提前约定长度;缺点是需处理分隔符冲突,解析效率略低。
  • 适用场景:文本协议(如日志传输、简单指令交互)。
3. 长度字段法(最常用,通用性强)
  • 核心逻辑:每个数据包分为 “头部 + 数据体”,头部固定长度(如 2 字节 / 4 字节),存储数据体的字节数,接收方先读头部获取长度,再按长度读取数据体。
  • 实现方式(C++ 示例):
// 发送方:打包(头部2字节存储数据长度)
std::string data = "hello tcp";
uint16_t len = htons(data.size()); // 网络字节序(大端)
send(sockfd, &len, sizeof(len), 0); // 先发送长度
send(sockfd, data.c_str(), data.size(), 0); // 再发送数据

// 接收方:拆包
uint16_t len;
recv(sockfd, &len, sizeof(len), 0); // 先读长度
len = ntohs(len); // 转换为主机字节序
char buf[len];
recv(sockfd, buf, len, 0); // 按长度读数据体
  • 关键注意:头部长度需固定,且要处理 “网络字节序(大端)” 与 “主机字节序(小端)” 的转换(htons/ntohs 函数)。
  • 优缺点:优点是通用性强、解析高效,无分隔符冲突问题;缺点是需额外处理头部,略增加开发量。
  • 适用场景:绝大多数场景(如即时通讯、文件传输、自定义二进制协议),是面试高频考点。
4. 应用层协议封装法(标准化,适合复杂场景)
  • 核心逻辑:基于成熟协议(如 Protobuf、JSON、XML)或自定义结构化协议,通过协议本身的格式定义边界。
  • 实现方式
    • 结构化协议(如 Protobuf):数据按字段编码,包含字段类型和长度,接收方按协议格式解析即可自动拆分;
    • 文本协议(如 JSON):以 {} 或 [] 作为逻辑边界,接收方解析 JSON 结构完成拆包。
  • 优缺点:优点是标准化、可扩展性强,支持复杂数据结构;缺点是解析开销略大。
  • 适用场景:分布式系统、跨平台通信、复杂数据交互(如微服务接口、客户端 - 服务器数据传输)。

核心原则与面试总结

  • 边界确定的本质是 “应用层协议约定”,TCP 本身不提供边界,需通过上述方法手动定义;
  • 面试优先选 长度字段法 作答(通用性强,能体现技术细节),需说明 “头部长度 + 网络字节序转换 + 数据体读取” 的完整流程;
  • 实际开发中,优先使用成熟协议(如 Protobuf)或成熟框架(如 Boost.Asio)的拆包机制,避免重复造轮子。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐