在 localhost 上观察 TCP 不具备“消息边界”

ネットワーク・RFCカテゴリを表すパンダのイラスト 网络・RFC

关于本文
本文是通过利用生成式 AI 的自动化生成流程创建的。在查阅了 RFC 9293 和 Microsoft Learn 的 TcpClient 官方资料的同时,通过在 localhost 上观察 TCP 的字节流,梳理了实际协议所需的“分隔”设计。

验证状态:📘 已确认官方规范・运行未验证

在 TCP 中,即使发送方调用了 Write 两次,也不能保证接收方能分两次将其接收。这是因为 TCP 处理的不是消息序列,而是有序的字节流

如果不了解这种差异,就会导致诸如“JSON 偶尔在中途截断”、“两件数据黏连在一起”等故障。

首先尝试

打开两个 PowerShell。

接收端:

$l = [Net.Sockets.TcpListener]::new(
    [Net.IPAddress]::Loopback,
    50555
)

$l.Start()
$c = $l.AcceptTcpClient()
$s = $c.GetStream()

$b = New-Object byte[] 1024
$n = $s.Read($b, 0, $b.Length)

[Text.Encoding]::UTF8.GetString($b, 0, $n)

$s.Dispose()
$c.Dispose()
$l.Stop()

发送端:

$c = [Net.Sockets.TcpClient]::new('127.0.0.1', 50555)
$s = $c.GetStream()

foreach ($x in 'HELLO', 'WORLD') {
    $b = [Text.Encoding]::UTF8.GetBytes($x)
    $s.Write($b, 0, $b.Length)
}

$s.Dispose()
$c.Dispose()

有时接收端会显示 HELLOWORLD,有时单次 Read 只能获取到中途的一部分。

发送次数与接收次数不对应

sequenceDiagram
  participant C as Client
  participant T as TCP byte stream
  participant S as Server
  C->>T: Write "HELLO"
  C->>T: Write "WORLD"
  T-->>S: Read "HELLOWORLD" のこともある
  T-->>S: Read "HEL" + 次のReadで残り のこともある

TCP 保证的是“顺序”和“可靠性”,而不是应用程序执行的 Write 边界。

尝试将缓冲区(buffer)设为 3 字节

将接收缓冲区缩减为 3 字节后,可以肉眼看出单次 Read 无法获取全部内容。

$b = New-Object byte[] 3

通过这个实验,我们会明白“只要 Read 一下就能完成一个消息”这种设计是危险的。

实际协议中如何进行分隔

有三种典型的方法。

方法示例特点
分隔符直到换行为止算 1 件适合文本
固定长度始终为 128 字节简单但灵活性较低
长度前缀(Length prefix)头部 4 字节为正文长度适合二进制 / API

例如,如果是换行分隔,则不是每次 Read 就将其字符串化并结束,而是将其积蓄在接收缓冲区中,把“到达换行符为止”的内容作为 1 件数据提取出来。

如何在工作中应用

  • TCP 套接字通信

  • 自研协议

  • 固定长度电文

  • 设备通信

  • 在 TCP 上传输的 JSON 或 CSV

  • 与旧业务系统的对接

仅凭“在测试环境中每次都能一次性接收成功”是不能作为正确实现的依据的。当通信量、操作系统、网络状况、发送时机发生变化时,分割单位也可能会发生变化。

注意事项

  • Read() 的返回值 n 是实际接收到的字节数

  • 并不一定能完全填满缓冲区大小

  • Read() = 0 是表示连接结束的重要状态

  • UTF-8 字符占用多个字节,因此也需要考虑字符边界

  • 在生产协议中确定最大消息长度

总结

  • TCP 是字节流,不保持消息边界

  • Write 次数和 Read 次数不一致

  • 应用层需要有分隔规则

  • 使用换行、固定长度、长度前缀等方式

  • 正确处理 Read 的返回值和连接结束

官方资料与第一手资料

文档信息

文章??
在 localhost 上观察 TCP 不具备“消息边界”
?布日期
更新日期
来源
https://papanda925.com/?p=15400&lang=zh

?可: ?于本站?有相??利的正文及原??表,除非?有?明,可依据 CC BY 4.0 使用。本文可能包含使用生成式AI?建或??的内容。若代??有?可声明,或?接的GitHub???定了?可,?代?以??可?准。引用内容、第三方?料、?片及商?不在本?可范?内。 使用政策

标题和URL已复制