最近自底向上学习网络模型,看到 TCP 层经常有人提到"粘包",我笑了

2020-02-29 15:52:34 +08:00
 asilin

那些探讨所谓 TCP 层“粘包”问题的同学们,你们为什么不问问他的兄弟第一层的“物理层”,是如何在物理介质里面处理载波信号的“粘包”的?

对于网络基础同学比较扎实的同学,就应该知道所谓的 TCP“粘包”是不存在的,数据要在 TCP 层流式传播,首先就应该做好“表示层”的边界定位工作,而且数据本身就应该是结构化的。

大部分探讨“粘包”问题的案例,都是直接 nc 一个 TCP 端口,开始灌入 ASCII 码文本,但数据的传输并不是这么用的,就算在 C 语言里面,复杂数据也得用结构体来存储吧,就算是 HTTP,也使用了“\r\n”来进行分隔,你就直接往里面灌,能不出现问题嘛。

12001 次点击
所在节点    程序员
84 条回复
scnace
2020-03-01 12:48:21 +08:00
别特么再粘了!这不是误导初学者吗😂 (话说粘包这个词有原始出处吗?
rio
2020-03-01 13:07:07 +08:00
「 TCP 粘包」有与之互补的「 UDP 分段」版本了 https://www.v2ex.com/t/648023
asilin
2020-03-01 13:18:40 +08:00
@rio 对,如果自底向上看,UDP 只不过是 IP+端口号 而已,本质上和 IP 数据包没有任何区别,没有附加任何功能。
GeruzoniAnsasu
2020-03-01 13:37:41 +08:00
@FrankHB 那首先得先给这两组词创造单独贴切的中文翻译
GeruzoniAnsasu
2020-03-01 13:47:31 +08:00
其实 “粘包” 这个现象很有意思
用文件 IO 来打比喻是不恰当的,因为你不可能遇到往文件里写了一篇文章然后往外读结果只读了个第一列函数就返回了导致文章狗屁不通的情况

大家都知道 TCP 是流的,但 write(&struct, sizeof(struct)) read(&strcut, sizeof(struct)) 可看不出来是流式的
sgissb1
2020-03-01 13:57:18 +08:00
@dndx 这个不需要,因为面试的时候小伙子很热衷于 leecode 的题,并且非常自信,而且面试中很多错误的术语和技术用词,也没有问任何工程实践问题。我都 8 年以上工作经验了,和其他家公司面试还真不一样,别家还会追加求证一下我的工程经验是否捏造 ^_^
rdZZZ
2020-03-01 14:17:40 +08:00
粘迟但到 :D
nicevar
2020-03-01 14:24:28 +08:00
老一辈程序员跟 TCP 打了十几二十年交道,突然看到这个新创造的词真的懵逼
jhdxr
2020-03-01 14:37:08 +08:00
@zsdroid 能够说出这个词的人,基本上都是在应用层( TCP/IP 四层模型,或者)处理数据,而不会是在 TCP 层(更准确的来说,传输层)的
FrankHB
2020-03-01 14:48:33 +08:00
@GeruzoniAnsasu

serialization 序列化
deserialization 反序列化
marshalling 列集
unmarshalling 散集

翻译不是问题,只是因为没多少人用所以才用原文。问题是原文意思就被普遍用错,而这个错误来自权威来源。
具体来说,I/O 是指系统内部和外部的交互。在一个系统内部交互的作用强行称为 I/O 会引发混乱。
这种误用的典型例子是,以抽象机语义指定行为的 ISO C++规定 I/O 操作(“库的 I/O 函数”)引发副作用——不管其实现是否改变了抽象机这个系统的状态。
这不科学。因为至少像 std::stringstream 这种( ISO C++所谓 Input/output library 里的)东西本来就不应该和系统外部交互,在这个定义下因为钦定副作用可能影响可观察行为而没法被优化成 no-op,即便实际可能什么都不用做。
再如,像格式转换之类的功能本来就该是 serialization/deserializaton,是应该能够证明不必要就该消除的东西。
真正的 I/O,是和设备交互的操作,操作的设备这种抽象机以外的接口。
这个意义下,C++的标准库 I/O 原则上设计就是错的,因为它违反了核心语言要求的抽象边界。让所谓标准 I/O 库函数比用户实现的 I/O 函数具有更加一等的地位也不可能是目的,何况在这里根本还没法直接优化。
这个问题从 C 就有,不过大概 stdio 隐藏了缓冲所以才没那么明显,以讹传讹惯了……
iEverX
2020-03-01 15:05:40 +08:00
可以说这种说法不准确,然而实际应用中,不可避免需要处理。

说 tcp 粘包,是因为 udp 没有这样的问题需要处理。因为使用 udp,必然会在应用层做应用协议包的拆分,收到 udp 包时,也得自己拼成一个应用协议包。不会有多个应用协议包在一个 udp 包发过来。

tcp 里,发送的时候,编码成字节流,收到的时候还是字节流。但是,对于程序员而言,字节流只是抽象,实际收到的仍然时一段一段的字节序列。这些字节序列不能直接用,必须解码成应用协议包。这里就的确会出现多个应用协议包在一段序列中的情况。decode 这个步骤,就是需要处理 byte[] 可能得各种情况。

这种情况下,称之为 tcp 粘包并不是问题,这个包本身指代就不是 tcp 的包。非得说 tcp 时字节流,所以没有包,过于死板。
dndx
2020-03-01 15:33:28 +08:00
@GeruzoniAnsasu 没看懂你这个比喻是想说明什么,TCP 的 socket API 默认就是阻塞的,你从里面读 x 字节系统在收到 x 字节之前也是不会返回的。这跟读文件流有什么区别?要不怎么 BSD socket 的 API 跟读写文件的都是兼容的呢,否则不如全部重新设计一套。
paoqi2048
2020-03-01 16:18:49 +08:00
你只看到了第二层,而你把他只想成了第一层,实际上,他是第五层
watzds
2020-03-01 16:22:49 +08:00
如果写书,字眼要扣好,特别严谨才行。平常讨论就抓住重点才是最重要的
rrfeng
2020-03-01 16:49:58 +08:00
所以楼主刚晋升为『粘包警察』,然后一下子出现了一堆『粘包监察』?
a852695
2020-03-01 18:58:27 +08:00
首先确定为概念本身是错误的;
然后讨论正确的是字节流;
仅此而已。
ajaxfunction
2020-03-01 19:06:42 +08:00
那我想问恩 鼠标上为什么没老鼠呢? 软盘为什么是硬的?
wangkai0351
2020-03-01 21:34:07 +08:00
@Mohanson 三本书一天看完, 我的天,仰望
yankebupt
2020-03-01 22:05:12 +08:00
@asilin 我一直覺得這是個僞命題,
天哪
直到我自己碰到了這個問題

這是一個 M11F 主板自帶的 AQC111C 5Gbps 網卡 win10 自帶驅動的 bug
當大數據量視頻串流的時候會立刻觸發這個問題
當使用某一**r 個協議轉 socks5 的中轉程序的時候不會觸發這個問題
使用另一個***ay 協議轉 socks5 的程序就會觸發這個問題
當觸發時網卡會 [直接罷工] 除非重新禁用

socks 是 tcp 的,外網協議也是 tcp 的。
唯一可能的可疑點估計就是用了流氓版 load balance,幾個出口 ip 不一樣,估計會有大量的 tcp retransmission 或報錯包夾雜在裏面。
[但也就是說,某一個純 tcp 的 pattern 會觸發這個網卡直接罷工的 bug。]

怎麼發現這個 bug 的呢?因爲把網卡 link 限定在 100M 物理層就不會觸發,1Gbps 就會...
換一塊 intel 的卡也不會觸發

查了一下,win10 自帶的 driver 版本之上,廠商發了兩個版本 patch,其中第一次的版本還沒完全補上這個 bug,第二個.18 版本才補上(我還不知道是不是完全補上了)

估計這就是你們說的黏包...
yuikns
2020-03-01 22:21:49 +08:00
@FrankHB 我的语文有点拙计了。
想确认一下 serializing / deserializing 和 marshalling / unmarshalling 这两套行为上没有区别吧?貌似我成对用,但是好像没有读到区别。
io 操作那应该是 read/write 那一套了?

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

https://www.v2ex.com/t/648625

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

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

© 2021 V2EX