当前位置: 首页 > news >正文

TCP 协议的“无消息边界”(No Message Boundaries)特性

TCP 协议的“无消息边界”(No Message Boundaries)特性,这是 TCP 与 UDP 等面向数据报协议的一个重要区别。

一、什么是“无消息边界”?

TCP 是一个 面向字节流(Byte Stream)的协议,它并不关心应用程序发送的数据是分成几次、每次发多少,也不保留这些数据的原始“分块”或“边界”。TCP 只保证:

  • 数据按 字节顺序 可靠传输;
  • 不丢失、不重复、按序到达;
  • 最终在接收端以一个连续的字节流形式呈现。

二、举例说明

假设应用程序(比如客户端)使用 TCP 连续发送了两条消息:

发送方依次发送:"Hello" 和 "World"

在发送时,可能调用了两次 send()write(),分别发送了 "Hello"(5 字节)和 "World"(5 字节)。

但是,接收方在调用 recv()read() 时,可能一次性收到:

"HelloWorld"(10 字节连在一起)

或者:

  • 第一次 recv() 收到 "HelloW"
  • 第二次收到 "orld"
  • 或者其他任意组合。

TCP 不会自动告诉哪 5 个字节是 “Hello”,哪 5 个字节是 “World”。它只是忠实地把所有字节按顺序传输给对方,但不会保留您发送时的“消息边界”。

三、为什么会出现这种情况?

因为 TCP 的设计目标是提供 可靠的、有序的字节流传输服务,而不是“消息”或“数据报”的传输。它不知道也不关心的应用层数据是如何组织的,它只负责将字节流完整无误地送达。

四、如何解决“无消息边界”问题?

既然 TCP 不保留消息边界,那么如果希望区分不同的消息(比如一条文本消息、一个命令、一个 JSON 对象等),就需要在 应用层自行设计协议来界定消息的边界。常见的方法有:

方法 1:固定长度消息

每条消息都采用固定字节数,比如每条消息都是 100 字节。接收方每次读取 100 字节,不足则等待。简单但效率低,不灵活。

方法 2:分隔符(Delimiter)

使用特殊的字符或字符串作为消息的分隔符,比如用 (换行符)、\0(空字符)或者自定义如 |||

  • 例如,每条消息以 结尾,接收方不断读取,直到遇到 就认为是一条完整消息。
  • 常用于文本协议,如 HTTP、Redis 协议的部分情况等。

⚠️ 注意:要确保消息内容本身不会包含分隔符,否则需要转义处理。

方法 3:长度前缀(推荐)

在每条消息的头部附加一个固定长度的字段,表示消息体的长度,比如用 4 个字节表示消息体有多少字节。接收方先读取这 4 个字节,解析出消息长度,再按照该长度去读取实际的消息内容。

🔧 这是最常用、最可靠、适用于二进制和文本协议的方案,比如:

  • 消息格式:[4字节长度][N字节内容]
  • 接收方先读 4 字节 → 得到长度 N → 再读取 N 字节内容

很多成熟的网络框架和协议(如 Protobuf over TCP、gRPC、自定义二进制协议)都采用这种方案。


五、对比 UDP

与 TCP 不同,UDP 是面向数据报(Datagram)的协议,它保留了发送时的消息边界:

  • 发送方调用一次 sendto() 发送 “Hello”,接收方调用一次 recvfrom() 就收到 “Hello”;
  • 发送 “Hello” 和 “World” 是两次独立的发送,接收也是两次独立的接收。

但 UDP 不保证可靠传输、不保证顺序、可能丢包,适用于实时性要求高但对可靠性要求不高的场景(如视频流、游戏、DNS 查询等)。


总结

特性TCP(面向字节流)UDP(面向数据报)
是否保留消息边界❌ 不保留,只传字节流✅ 保留,一次发送对应一次接收
可靠性✅ 可靠传输,有序,不丢包❌ 不可靠,可能丢包、乱序
通讯方式点对点连接无连接
适用场景文件传输、网页、API通信等需要可靠性的场景实时应用、广播、视频流等

✅ 建议

如果使用 TCP 进行应用开发,一定要在应用层自己处理消息边界问题,推荐使用 长度前缀法 来明确每条消息的起始和长度,这是最通用、可靠的方式。

http://www.dtcms.com/a/314061.html

相关文章:

  • sqli-labs-master/Less-31~Less-40
  • 内联函数:提升效率的空间换时间艺术
  • 移动端 WebView 视频无法播放怎么办 媒体控件错误排查与修复指南
  • 官宣!多功能DC-DC数字电源控制器重磅首发
  • 应用药品GSP证书识别技术,提升药品流通各环节的合规管理效率和风控水平
  • 数据工程与处理:AI时代的数据基石与智能化管道
  • java~final关键字
  • doris `unicode` 是多语言混合类型分词与elasticsearch分词差异
  • Java从入门到精通 - 算法、正则、异常
  • MQTT:安装部署
  • 【AI 加持下的 Python 编程实战 2_13】第九章:繁琐任务的自动化(中)——自动批量合并 PDF 文档
  • CMake进阶: 使用FetchContent方法基于gTest的C++单元测试
  • Docker-07.Docker基础-数据卷挂载
  • 在CAPL自动化脚本中巧用panel函数
  • 关键领域软件研发如何构建智能知识管理体系?从文档自动化到安全协同的全面升级
  • 实现Trie(前缀和)C++
  • 【REACT18.x】封装react-rouer实现多级路由嵌套,封装登录态权限拦截
  • PyTorch :三角函数与特殊运算
  • python:讲懂决策树,为理解随机森林算法做准备,以示例带学习,通俗易懂,容易理解和掌握
  • 张 事实关注增强模型:提升AI准确率新方法
  • 设备电机状态监测中的故障诊断与定位策略
  • 【AI论文】VL-Cogito:面向高级多模态推理的渐进式课程强化学习
  • Redis之Hash和List类型常用命令
  • [特殊字符] Ubuntu 下 MySQL 离线部署教学(含手动步骤与一键脚本)
  • 小鹏汽车前端面经
  • 笔记本电脑联想T14重启后无法识别外置红米屏幕
  • 【银河麒麟服务器系统】自定义ISO镜像更新内核版本
  • Axure日期日历高保真动态交互原型
  • Axure设计Web端新增表单页面模板案例
  • 蚂蚁S9矿板引脚定义