以太网中的 MTU 与 MSS

以太网(Ethernet)最大的数据帧是 1518 字节。以太网帧的帧头的 14 字节和帧尾 CRC 校验 4 字节共占了 18 字节,剩下的承载上层协议的地方也就是 Data 域最大就只剩 1500 字节。这个值我们就把它称之为 MTU。MTU 的全称是 maximum transmission unit(最大传输单元)。MTU 可以认为是网络层能够传输的最大 IP 包。

而 MSS(Maximum segment size)可以认为是传输层的概念,也就是 TCP 数据包每次能够传输的最大量。为了达到最佳的传输效能,TCP 协议在建立连接的时候通常要协商双方的 MSS 值,这个值 TCP 协议在实现的时候往往用 MTU 值代替(需要减去 IP 数据包包头的大小 20Bytes 和 TCP 数据段的包头 20Bytes)所以往往 MSS 为 1460。通讯双方会根据双方提供的 MSS 值得最小值确定为这次连接的最大 MSS 值。

MSS 为 1460 是由 1500-20(IP 头)-20(TCP 头)计算出的。但是在实际场景下,TCP 包头中会带有 12 字节的选项 -- 时间戳(用户在发送每一个 TCP 报文的时候都放置一个时间戳,接受方在确认中返回这个时间戳值。发送方就可以根据这个时间戳来计算 RTT(往返传输时间 -- 发送端从发送 TCP 包开始到接收到它的立即响应所耗费的传输时间.)。从而使得 RTT 更加精确,减少不必要的重传。减低网络的负载。)

这样,单个 TCP 包实际传输的最大量就缩减为 1448 字节。1448=1500-20(IP 头)-32(20 字节 TCP 头和 12 字节 TCP 选项时间戳)。

问题来了:“每个 TCP 包在理论上应该能打包更多数据才对,但是实际场景下 TCP 传输为什么会以这个 1448 作为打包单位呢?”

理论上,单个 TCP 包能打包的数据量远远多于 1448 字节,现在为了适应 MTU,只要在以太网上跑 TCP,系统就默认最大以 1448 字节打包 TCP。

假如我们用更大的数据量来打包会有什么结果呢?
答案是降低了传输效率。

超过 MTU 的大包反而降低效率的原因如下:

IP 层非常关心 MTU,因为 IP 层会根据 MTU 来决定是否把上层传下来的数据进行分片。就像一条运输线路的承载能力是有限的,碰到大东西要运输,只能把大东西拆开成为散件,分开运输,到达目的地之后还必须能再次组装起来。

当两台远程 PC 互联的时候,它们的数据需要穿过很多的路由器和各种各样的网络媒介才能到达对端,网络中不同媒介的 MTU 各不相同,就好比一长段的水管,由不同粗细的水管组成(MTU 不同 :))通过这段水管最大水量就要由中间最细的水管决定。
对于网络层的上层协议而言(我们以 TCP/IP 协议族为例)它们对水管粗细不在意,它们认为这个是网络层的事情。网络层 IP 协议会检查每个从上层协议下来的数据包的大小,并根据本机 MTU 的大小决定是否作 “分片” 处理。分片最大的坏处就是降低了传输性能,本来一次可以搞定的事情,分成多次搞定,所以在网络层更高一层(就是传输层)的实现中往往会对此加以注意!

这个就是在以太网上,TCP 不发大包,反而发送 1448 小包的原因。只要这个值 TCP 才能对链路进行效能最高的利用。