TGTGInsighttelegram intelligenceLIVE / telegram public index
← Hypercube's Channel
Hypercube's Channel avatar

TGINSIGHT POST

Post #111

@SmartHypercube_channel

Hypercube's Channel

Views317帖子阅读量
发布9月30日2023/09/30 04:50
Post content

帖子内容

新手常犯的一个错误是以为 TCP 可以用于传输多个小字节串,以及它们之间的边界,类似这样: [字节, 字节, 消息边界, 字节, 字节, 字节, 字节, 消息边界] 以为整个序列要么完整传输到另一端,要么某个前缀加上 RST 会被传输到另一端。实际上,TCP 没有消息边界的概念,发送方先发送 2 字节,再发送 4 字节,接收方完全有可能先看到前 3 个字节,再看到后 3 个字节(只保证总共 6 个字节连起来是按顺序正确传输的)。 但是,很多人可能都不太了解的另一种错误是,以为 TCP 可以用于传输任意长的连续字节串,加上 FIN 作为结束标志: [字节, 字节, 字节, 字节, FIN] 以为整个序列要么完整传输到另一端,要么某个前缀加上 RST 会被传输到另一端。于是不设计发送消息长度或结束标志的机制,而是发送方一直发载荷,发完了就 shutdown,以此表示载荷结束了。接收方一直收,直到看到 EOF。 按我的理解,只考虑 TCP 的语义时,这个想法其实是没问题的,然而操作系统会打破这个假设。如果发送方的进程被信号杀死,操作系统会自作主张地给这个进程的所有 TCP 流发一个 FIN(而不是 RST)。上面说的错误的设计会导致当发送方进程被杀死时,接收方收到不完整的载荷,却以为是完整的。一个很坑的例子是 @zzh1996 提到 HTTP 协议规定服务器可以不返回 Content-Length 也不用 chunked,这种情况下以 FIN 作为载荷结束的信号,可能导致客户端只下载到半个文件就以为下载成功了。 所以结论是,如果用 TCP 传输一串字节,实际上可能在传输了任何一个前缀后,突然传输一个 FIN 或 RST。没有手段可以可靠地分辨收到的是完整内容还是某个前缀,FIN 和 RST 在这一点上是没区别的,在我看来这是操作系统设计的一个错误。