TCP recv 出来的数据会错乱吗?

2021-08-13 13:56:51 +08:00
 z1113456051

服务器(CentOS 6.10)出现了偶现的 TCP 数据解包失败,用 tcpdump 抓包看到,出问题每次都是在 Seq 不连续的那个包。

例如收到包的顺序是 3 4 2 。recv 出来的数据顺序也是 2 3 4,但是这时候的 3 的数据内容就错乱了。

日志加在 /netio/epoll/tcpcarrier.cpp 。TCPCarrier::OnEvent 的 ReadFromTCPFd 的下一行。

目前怀疑 recv 和 iobuffer,已经补了日志在 recv 的下一行,不过这个问题还没有再次出现。

这个问题是偶现的,并不是每次出现[TCP Previous segment not captured]都会有问题

取数据代码 recv(fd, (char *)(_pBuffer + published), expected, MSG_NOSIGNAL)

第一次问题

// 这个包还是正常的。抓包数据和程序内 recv 后的日志都还是对的上的

68691 1885.443261 TCP 102 37001 → 33118 [PSH, ACK] Seq=1965201 Ack=1801824 Win=12987 Len=36 TSval=206775456 TSecr=2087966452 data:2400000010400000000000000000000013204000f5340a616d880000000001005f8e1b00

68692 1885.444510 TCP 66 37001 → 33118 [ACK] Seq=1965237 Ack=1801882 Win=12987 Len=0 TSval=206775457 TSecr=2087966481

// 从这里开始不对了

// 这个包的数据在日志中搜不到了(应该是这个包的数据错乱了,放在 recv 的数据中间)

68693 1885.593978 TCP 115 [TCP Previous segment not captured] 37001 → 33118 [PSH, ACK] Seq=1965273 Ack=1801882 Win=12987 Len=49 TSval=206775606 TSecr=2087966481 data:310000001a400000000000000000000001a60f0a617ecf000000000000b9227f00000001004ce979000100000000000000

68694 1885.599328 TCP 115 37001 → 33118 [PSH, ACK] Seq=1965322 Ack=1801882 Win=12987 Len=49 TSval=206775612 TSecr=2087966631 data:310000001a400000000000000000000001a60f0a617ecf000000000000b9227f0000000100c9f76c000100000000000000

68695 1885.794432 TCP 102 [TCP Retransmission] 37001 → 33118 [PSH, ACK] Seq=1965237 Ack=1801882 Win=12987 Len=36 TSval=206775807 TSecr=2087966637 data:24000000104000000000000000000000b9227f00a60f0a617ecf0000000001005c817b00

// 这是 recv 后日志的打印,这一次一共获得了 3 个包的数据,68695 在这次 recv 的数据的前面,68694 在后面。但是中间多出了一段乱的数据,同时 68693 的数据找不到了,中间错乱的数据长度还正好和它一样。

24000000104000000000000000000000B9227F00A60F0A617ECF0000000001005C817B00A061DFDFB279F68C070442DA5C819A00100021927FAC089265FA711C8E5563F23330ED971033E5AD86F70BC9A62C5D8CB0310000001A400000000000000000000001A60F0A617ECF000000000000B9227F0000000100C9F76C000100000000000000

第二次问题

// 这个包的 tcpdump 和程序内 recv 后的日志是对的上的

167466 3133.986731 TCP 94 37001 → 40534 [PSH, ACK] Seq=5021467 Ack=4605653 Win=12482 Len=28 TSval=233223981 TSecr=2114414994 data:1c00000012400000000000000000000043fd7e00c2a10a61cb1d0000

// 从这里开始不对了

// 这个包的数据在日志中搜不到了(应该是这个包的数据错乱了,放在这一次 recv 的数据的中间)

167467 3134.082772 TCP 102 [TCP Previous segment not captured] 37001 → 40534 [PSH, ACK] Seq=5021531 Ack=4605653 Win=12482 Len=36 TSval=233224077 TSecr=2114415046 data:24000000104000000000000000000000123531001e9a0a6171f200000000010017d87d00

167469 3134.237788 TCP 102 [TCP Retransmission] 37001 → 40534 [PSH, ACK] Seq=5021495 Ack=4605653 Win=12482 Len=36 TSval=233224233 TSecr=2114415124 data:2400000010400000000000000000000040d17d0059710a61914e000000000100fb101b00

167468 3134.104359 TCP 102 37001 → 40534 [PSH, ACK] Seq=5021567 Ack=4605653 Win=12482 Len=36 TSval=233224099 TSecr=2114415102 data:24000000104000000000000000000000fd053300dd780a61c30300000000010022987900

// 和第一次差不多,这次 recv 的日志,一次 3 个包的数据,167469 和 167468 的数据是对的分别在收尾。但是中间多出了一段乱的数据,同时 167467 的数据不见了。

24000000104000000000000000000000FD053300DD780A61C303000000000100229879008060068F405C6A200B0B4F063C85B820014FFCC7E96A28A0036DEE25CD7BED8EDBFD576A2400000010400000000000000000000040D17D0059710A61914E000000000100FB101B00

868 次点击
所在节点    问与答
3 条回复
zhuifeng1017
2021-08-14 07:55:05 +08:00
tcpdump 抓取的是网卡数据,理论上不会有问题。
问题只可能是 recv 代码问题。考虑多线程,recv 粘包等原因
z1113456051
2021-08-14 11:52:33 +08:00
@zhuifeng1017

只能先等下一次出问题,这样就能确定 recv 取出来就是错误的了。
julyclyde
2021-08-18 11:47:00 +08:00
recv 不可能顺序错乱

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

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

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

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

© 2021 V2EX