多路径 TCP 让应用看见一条双向字节流,同时允许这条连接使用多条 TCP 子流。每一条子流在网络上仍是一次普通的 TCP 握手,选项里带有多路径信息。截至 2026 年 10 月,现行文本是 RFC 8684。它取代 RFC 6824 所规定的 v0,v1 与 v0 不向后兼容。

应用看见一条,网络看见多条

一个可独立引用的定义句:多路径 TCP 连接是一组一条或多条的子流,应用经它在两端之间通信。连接与应用套接字一一对应。子流是在单条路径上传送的 TCP 段序列,建立和结束的方式与普通 TCP 相同(RFC 8684)。

对网络层,每条子流看起来就是一条普通 TCP,只是段上带了一种新的 TCP 选项。选项共用 IANA 登记的 Kind 30,具体消息靠 4 位子类型区分。v1 的子类型登记在 RFC 8684 第 7.2 节;v0 的子类型仍要回头看 RFC 6824。

子类型符号用在什么时候
0x0MP_CAPABLE只在第一条子流的握手里,声明会多路径并交换密钥
0x1MP_JOIN后续子流用来加入已经存在的连接
0x2DSS携带数据序号映射,以及连接级确认
0x3ADD_ADDR通告一个地址,不必立刻打开子流
0x6MP_FAIL回退

0x4、0x5、0x7、0x8 分别是撤回地址、改变子流优先级、快速关闭和子流复位。本文不展开这四项的状态机。

RFC 8684 假定:主机有多个地址,就足以认为存在多条路径。这些路径可以共享路由器。设计也允许用端口区分路径,因为有的等价多路径会把不同端口散列到不同下一跳。散列本身见 等价多路径。

第一条子流先问对端会不会

MP_CAPABLE 的子类型是 0x0。同一字节里剩下的 4 位是版本,本规范是 1。它出现在第一条子流的 SYN、SYN/ACK 和 ACK 上。后续子流不再用它。

密钥在这条握手里以明文放进选项,用来认证以后要加入的子流。RFC 8684 写明,除快速关闭外,这是密钥唯一一次以明文出现在线路上。以后的子流用 32 位令牌标识连接,不再发送这把密钥。密钥必须难猜,并且在这台主机当前的全部多路径连接里唯一。如何生成由实现决定。

在本文所依据的 HMAC-SHA256 下,令牌必须是这把密钥的 SHA-256,取最高 32 位。初始数据序号必须是同一哈希的最低 64 位。密钥按网络字节序参与哈希。以后若协商了别的算法,令牌算法可以不同。RFC 8684 还写明,两把不同的密钥可能哈希到同一个令牌;最坏情况下新子流加不上,原连接仍继续提供普通 TCP 服务。这是该节的判断,不是 2026 年 10 月的测量。

一个可独立引用的定义句:SYN 含有 MP_CAPABLE 而 SYN/ACK 没有时,必须把会话当作普通的单路径 TCP。SYN 没有该选项时,SYN/ACK 不得回应一个。第三次握手的 ACK 也没有时,必须回退到普通 TCP。实现可以在做出回退决定之前多次尝试发送这些选项(RFC 8684 第 3.1 节)。

握手任一方若认为协商已被破坏,例如中间盒改坏了 TCP 选项,或出现意料之外的确认号,主机必须停止使用多路径 TCP,并且以后的段里不再带这些选项。在成功收到一份 DSS 之前,不得建立新子流。

标志位里,H 表示 HMAC-SHA256。只支持这一种的实现必须把 H 置 1,并把 D 到 G 置 0。D 到 H 全为 0 时,这份 MP_CAPABLE 必须当成无效并忽略,握手退回普通 TCP。响应方只回一个被选中的算法位。它一个都不支持时,必须不带 MP_CAPABLE 地回应,从而回退。

C 位为 1 表示发送方不接受再向这个源地址和源端口加入子流,接收方不得向这一对地址和端口发起额外子流。RFC 8684 举的例子包括发送方位于严格的 NAT 之后。这是握手时的声明,不是一份 NAT 映射分类,映射行为见 VPN NAT 穿越。

后来的子流拿令牌加入

任一端都可以发起新子流。RFC 8684 预期通常由最初发起连接的那一端来做,并把它写成经验规则,不是一条禁止另一端发起的必须。

新子流仍是普通的三次握手,SYN、SYN/ACK 和 ACK 里带 MP_JOIN,三次的格式各不相同。SYN 里的令牌用来指出要加入哪一条连接:发起方发送的是由对端密钥导出的那个令牌。HMAC 使用 MP_CAPABLE 里交换的密钥,以及这次 MP_JOIN 里的随机数。选项里还有地址标识。它让发送方用一个本地编号指称源地址,而不必先知道这个地址有没有被 NAT 改写。

主机也可以先通告地址、暂不建子流。ADD_ADDR 带有 HMAC,接收方回显以表示收到。地址标识和这次通告回答的是「端点如何称呼自己的地址」。出口在拆隧道之后改写内层源,是另一跳,见 出口 NAPT。某一出口会不会改掉子流的源端口,本文没有测量。

数据序号和子流序号不是同一套

一个可独立引用的定义句:多路径 TCP 用 64 位数据序号给整条连接上的数据编号。每条子流仍用 TCP 头里自己的 32 位序号。DSS 里的映射说明:从哪一个子流序号开始、对应哪一个数据序号、这段映射覆盖多长。同一数据序号可以在另一条子流上重传(RFC 8684)。

确认也有两级。子流上的普通 TCP 确认,只确认这一条子流收到了哪些段。连接级的数据确认,跟踪字节流前进,并滑动接收窗口。所有子流共享同一个接收缓冲区,并且通告同一个接收窗口。

子流内部仍是 TCP。某一段没到时,子流自己的选择性确认怎么读,见 TCP SACK。那一份确认不代替连接级的数据确认。

要关掉一条子流、但保留整条连接,用的是这条子流上普通的 FIN。要表示整条连接没有更多数据,则在 DSS 里带上数据 FIN。它的语义与 TCP 的 FIN 相同,作用在连接级。

RFC 8684 把多条路径上的拥塞控制指到 RFC 6356,那份文档给出一种耦合算法,目标是使用多条路径时不损害其他用户。它不是 RFC 8684 正文里唯一写死的实现。某一系统在 2026 年 10 月用的是哪一种,本文没有测量。单条路径上的窗口和算法见 拥塞控制。

校验和用来发现载荷被改过

MP_CAPABLE 的 A 位表示要求校验和。除非管理员已判定不需要,例如环境可控且没有会改载荷的中间盒,否则 A 应当置 1。只要有一端要求,就必须使用。只有两端在各自的 SYN 里都把 A 置 0,才可以不用。若一端不想用校验和,却收到 A 为 1,它必须把这份 MP_CAPABLE 当成无效并忽略,从而回退到普通 TCP。

协商使用之后,DSS 里的校验和覆盖这段映射的数据,再加上一个伪首部,算法是普通的 TCP 校验和。它用来发现不理解多路径 TCP 的中间盒是否改动过载荷。校验失败会让子流失败,或按第 3.7 节回退,因为接收方已经不能可靠地知道子流序号空间。未启用校验和时,中间盒若改了段边界、改了内容或漏送了映射所覆盖的段,损坏的数据可能被交给应用。因此,除非已知路径上没有这种设备,否则建议使用校验和。

回退的一种做法是无限映射:把 DSS 的数据级长度设为保留值 0,校验和也置 0,从而把这条子流剩下的数据一直映射到连接级。握手阶段选项被丢掉时,也会退回单路径 TCP。

隧道把子流收进同一条外层

子流用哪一个源地址,取决于主机当时为这次握手选出的地址,见 源地址选择。全隧道若把默认路由指向虚拟接口,新的子流仍可能从这张接口出去。到 VPN 服务器的路径上,它们共用外层那一对地址和端口。等价多路径若只散列外层头,这些子流在这一段不会被拆开。拆封装之后,内层五元组重新可见,后面的设备才能再按子流区分。

外层是一条 TCP 还是一条 UDP,见 VPN 用 TCP 还是 UDP。那是设备到节点的封装。多路径 TCP 若出现,出现在被封装的内层,或出现在某条本身就用 TCP 的外层上。本文没有测量哪一个客户端会把外层做成多路径 TCP。

手机从一张物理接口换到另一张时,源地址会变。多路径 TCP 可以在新地址上再开子流。VPN 外层会话能不能跟着这次切换继续,是另一件事,见 Wi-Fi 与蜂窝网切换。隧道图标不表示这条 TCP 已经有第二条子流。

一个可独立引用的结论句:多路径 TCP 增加的是同一条应用连接下的 TCP 子流。它不表示 VPN 已经同时占用 Wi-Fi 和蜂窝网,也不表示这些子流绕开了封装。

本文不提供打开多路径 TCP、绑定接口或让子流绕开隧道的步骤。

现象对照

现象更可能先看什么
应用只有一个套接字,线路上有多个五元组且带 Kind 30一条连接下的多条子流
SYN 有 MP_CAPABLE,SYN/ACK 没有,之后也不再出现这些选项按规范回退到单路径 TCP
两条子流的 TCP 序号各自连续,应用仍按序收到字节子流序号和 64 位数据序号是两套
许多子流的外层地址都是同一台 VPN 服务器封装把它们收成一条外层流
换了物理接口后出现新的 MP_JOIN有人在新地址上加入子流。VPN 外层是否还活着要另看

核对清单

  1. 先分清连接和子流:套接字对应连接;网络上的每一条 TCP 是子流;
  2. Kind 30 不够:还要看子类型。第一条是 MP_CAPABLE,后来的是 MP_JOIN;
  3. 对端不会多路径时,握手仍可完成:缺选项就按普通 TCP 继续;
  4. 序号有两套:子流是 32 位,连接是 64 位,重传可以换子流;
  5. 全隧道不自动变成多条外层路径:子流在到节点之前可能共用同一条封装。