怎么理解 TCP 粘包与拆包?

2021-01-23 18:40:22 +08:00
 narutow

记得一个大佬跟我说过, "TCP 哪有什么粘包拆包的问题, 人家本来就是流式协议, 你用它传你的结构化数据, 你是做数据的序列化和反序列化, 而不是在克服 TCP 的缺点."

这样的理解是否准确呢, 大家什么看法. 本菜鸡感到疑惑~

11833 次点击
所在节点    问与答
99 条回复
exiledkingcc
2021-01-24 22:10:58 +08:00
@micean 你这是典型的错误认识。
liuminghao233
2021-01-24 22:37:00 +08:00
我倒是认为 TCP 流的 feature 是不必要的
大多数 tcp 应用都在应用层做 tlv
协议栈完全可以禁止段分割与合并
对确认机制进行修改
让 TCP 变成是 Datagram
这样的话应用层就不用关心所谓的粘包问题了
no1xsyzy
2021-01-24 22:52:33 +08:00
@eastphoton 补充啦补充
真要说 “流拆成包” 这个组合挺诡异的,但似乎找不到好词来区分
parse: bytes->struct
split: bytes->bytes[]
framing: stream[byte]->stream[bytes]
三种情况(实际上第三个词英文也挺诡异的,不知道有无更好说法)
结果上来说,这边简直是一堆不够严谨的动词和名词的大杂烩。
muzuiget
2021-01-24 22:54:40 +08:00
月经问题,已经回答无数次了。
no1xsyzy
2021-01-24 23:03:55 +08:00
@liuminghao233 这点上来说,一来有 SCTP
二来,其实 TCP 和 UDP 分别是两种 tradeoff 。这是 feature,但是是 tradeoff feature,不是因为做成这样好,而是因为做成这样能让其他地方更好。
允许段分割和合并还有一个效果,比如你每个报文比 IP 包大小还大一个字节,某一秒发 N 个报文(比如 20<N<30 ),如果你不允许段分割与合并,将导致你发出 2N 个 IP 包,其中一半只用于发一个字节。允许分割合并就只用发 N+1 个 IP 包。现在不怎么在乎,当时可能会很吃紧。
liuminghao233
2021-01-24 23:31:01 +08:00
@no1xsyzy
我还没用过 sctp 不知道能不能过 nat
除了 udp tcp 其他的不好说

小包问题我想知道你说的情况有实际应用吗
我觉得对于需要 tlv 编码的应用来讲
用流语义好像并没有带来收益
no1xsyzy
2021-01-25 00:33:22 +08:00
@liuminghao233 形态上与 TCP 一致,支持应当是可以的,也有在 TCP / UDP 上再做一层的……

包大小变换问题其实会发生在 MTU 改变、以及数据通过隧道导致内外包限不同的情况
前提条件是 TLV 的话确实流没什么好处,流是为了避免这一层作太多强制。
算是历史原因。
如果大家都用 SCTP 或者 SCTP 比 TCP 、UDP 更早被设计出来的话也没 TLV 这茬了。
neoblackcap
2021-01-25 00:48:30 +08:00
@no1xsyzy SCTP 据我了解,也就是运营商在自己内部的一些网里面用。广义的网络,各种设备是针对 TCP 以及 UDP 来设计的,设备里面是有 ASIC 去处理 TCP/UDP,SCTP 没有这些硬件加成,速度立马下降。
这也是为啥 QUIC 会设计在 UDP 之上,而不是另起炉灶。
littlecreek
2021-01-25 04:32:16 +08:00
@Mutoo 谢谢
lewis89
2021-01-25 06:34:56 +08:00
@neoblackcap #88 那就没毛病了,说白了 就是 IPv4 时代,大部分路由器跟硬件平台 只针对 UDP 跟 TCP 设计了,实际上也就是 UDP 跟 TCP 成为事实标准了
lewis89
2021-01-25 06:36:49 +08:00
@neoblackcap #88 一般家用应该都是依赖硬件 NAT 转发,可能真没有为 SCTP 设计过
lewis89
2021-01-25 06:40:36 +08:00
其实楼主只要想清楚一个问题就行了,http 是依赖 TCP 设计的,你看 http 报文头里面有一个 content-length 实际上就是用来干 沾包 黏包 拆包 这个事情,因为对于 http 服务器来讲,真正的报文协议是一个 http 头 + http body, 但是流式传输 如果没有截断流的机制 就会变成 http 头 + http body + 下一个 http 头的一部分 ,这样解析 tcp 流就会报错,所以 content-length 就是用来干这个事情的。
no1xsyzy
2021-01-25 10:55:14 +08:00
@neoblackcap ASIC 是盲点
确实,消息传递还是 WebSocket 吧
或许哪个平行世界有 SCTP 是事实标准,也就没有粘包问题和粘包警察了(能瞎争的东西多了去了,没什么意义
julyclyde
2021-01-25 12:28:39 +08:00
这基本上是个信仰问题
你要是信仰流,那么看啥都像流流
如果信仰包,看啥都像包,而且还有粘包的问题
byaiu
2021-01-25 12:30:53 +08:00
@soulzz 一个 fd 只能关联一个 socket 吧
xuboying
2021-01-25 12:51:13 +08:00
打个买东西的比方,你网上买了 20 个东西,去快递点取的时候(按顺序)可能拿到 1 件可能拿到 5 件可能拿到 10 件,件数的事情你不能控制,快递也没有义务确定一次送到的件数
TCP 是好一点的快递,只保证不丢件,或者至少丢了会负责再补发
UDP 么丢了就丢了。
auto8888
2021-01-25 14:20:19 +08:00
TCP 不就是一把收了 5 个货 需要自己分一下吗。。。居然还有警察的吗
julyclyde
2021-01-26 10:47:56 +08:00
@auto8888 问题在于并不见得一次五个,也可能是一次收到 0.35+1+1+1+1+0.87 这样
auto8888
2021-01-26 13:37:09 +08:00
@julyclyde 确实,TCP 只保证报文的先后顺序

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/747735

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX