为什么 wireshark 里面看到的 tcp 包那么长

我们经常用 wireshark 去分析 tcp dump, 有时候, 我们会看到有些不符合我们直觉的事情, 比如下面的截图中, 你看到这个 tcp 包竟然有 36200 字节.
tcpSoLong.png

tcp 包的长度是由这个 tcp 连接在建立的时候, 2 端协商(通知更合适)而来的, 取其中小的值. 通常情况下我们接触到的都是以太网, 所以这个长度(MSS:maximum segment size)基本是 MTU(maximum transmission unit) 1500 - 20 -20 = 1460 字节. 如下图所示:
syn_mss.png

那么, 为什么我们会在 wireshark 分析里面看到远远大于 1460 的 tcp 包呢?

  1. 难道 tcp 层直接把大包甩给 IP 层, 让 IP 层自己去分拆?
    tcp 层定义 MSS 的意图就是直接分片(Segment), 把自己分成适合 IP 层的包, 然后直接交给 IP 层发送, 这样 IP 层就不需要关心拆成小包这种事情, 直接做最简单的事情, 把需要拆成小包的性能开销转移给上层. 这样也是 MSS 的意图所在, 所以不是这个原因.
  2. 难道是传说中的 Jumbo frame?
    通常情况下, Jumbo frame 可以做到大小 9000 字节, 当然再大一些也可能. 不过这要中间的所有网络设备都支持这么大的 frame, 否则么有任何效果. 我们这个例子里, 并不是这原因.

真实的情况是:

这是一种网络优化技术: [TCP Segmentation Offloading][3]. 没有优化之前, 这种 TCP 包的分片(segmentation) 应该是 kernel 里面来做的, 这就需要消耗 CPU 资源, 采用 TCP Segmentation Offloading 之后, 这种事情都交由网卡去做了, 网卡集成了某些计算芯片, 做这个就不在消耗 CPU 资源了. 应用层直接把数据甩给网卡, 网卡做 TCP 分片, 封装成 IP 包, 然后在数据链路层封包发送. 可是做 tcp dump 的工具, 比如 tcpdump, wireshark, tshark 之类的工具并不知道这个情况, 它们只需要从网卡层读传入和传出的数据, 当它们读数据的时候, 这个包网卡还没处理, 所以你看到的就是大包. 如果去做 CRC 校验, 校验也是出问题的. 

这个问题是由下面这个文章讲明白的, 更多详细内容, 可以参看他的文章:
The drawbacks of local packet captures

以下这个图片就出自上面这个文章:
Offloading.gif

关于发送端网卡层处理大包拆小包: https://en.wikipedia.org/wiki/Large_send_offload
关于接收端网卡处理小包合并为大包: https://en.wikipedia.org/wiki/Large_receive_offload

标签: none

添加新评论