之前做过把MPTCP协议移植到LWIP协议栈中的工作。其实就是移植LWIP到android环境下再把MPTCP的实现从内核中porting过来。不过根据两个协议栈的特性不同,这一协议相当于是重新实现了一遍。

一、MPTCP简介

随着移动互联网的引入,互联网已经发生了显著的变化,多路径的讨论主题也转移成了许多移动相关的问题。移动设备上附着着许多 IP 地址。蜂窝无线接口上也有 IP 地址集。这些“智能”设备中许多也有 WiFi 接口,也有可能有 IPv4 和 IPv6 地址。还可能会有具有 IP 地址的蓝牙接口,兴许还有一些 USB 的网络接口。当启用时每一个网络接口都需要其本地 IP 地址。我们现在所处的互联网中设备具有多个可用 IP 地址是相对较为普遍的。但我们如何利用这些地址呢?

如果一个端到端的会话能使用多地址,而且以此推理也能使用到多接口。那么应用就可以在移动数据链路和WiFi之间进行无缝数据传输,或者可以同时利用两链 路进行传输。假如接口的 IPv4 地址和 IPv6 地址是等同地位的,那么在两种协议之间进行无缝地数据传输也是可实现的。至于在某个时刻使用哪种传输服务不再由移动运营商或者 WiFi 运营者,或者设备,或者运行的操作系统决定。如果应用能够使用到多地址,多协议和多接口,那么应用自身就可以根据各个连接是关闭还是可用状态来决定怎样选 择连接才能最好的满足自身需求。

Multipath TCP (MTCP) 初始双方会交换信息来确保双方都支持这个机制,允许双方使用额外的链路或者通道。在应用允许的前提下,可以立刻使用这些链路来完成通信。

二、MPTCP原理

Multipath TCP的基本思路是把发送的流量切分为更多的子流量,每个子流量建立一个单独的端对端会话,然后在远端把接收的子流量重新整合成单个流量。

MPTCP可以像 TCP一样的模式工作,生成多个子流量,然后把数据分配给单独的子流量,这种机制对于上层应用程序来说是不透明的。应用程序可以通过 API 在链路池中添加和删除地址,但不能直接管理和操作 MPTCP。MPTCP 保证了低层级的TCP组件不会受到影响,即 MPCTP子流量是传统的 TCP 流量。从数据发送者的角度来说,MPTCP把来自应用程序的数据流切分成了一个个数据块,再把单个数据块封装到了单个子流量中。从数据接收者的角度来说,MPTCP收集了TCP子流量里的数据块,并且重新组装成原始数据流,并传递给本地应用程序。

报文结构

MPTCP存在于tcp的option字段中,再tcp连接的过程中。如果激活此功能双方服务器再tcp连接阶段会额外进行mptcp的协商。

连接

 

主机会向远端主机会发送一个 SYN 消息,在 MPTCP 选项字段里包含了一个MP_CAPABLE 信号。如果远端主机也支持 MPTCP,远端主机会返回一个 SYN+ACK 响应,同样在MPTCP 选项字段里包含了一个 MP_CAPABLE 信号。会话使用了 ACK 和 MP_CAPABLE 信号完成 TCP 和 MTCP 握手过程,确保两端都得到了对方的 MPTCP 会话数据。在整个会话过程中,两端交换了 64 位字节的会话密钥,同时各自生成一个 32位的哈希共享密钥。两个主机之间随后使用子链路的时候会用到这个共享密钥。

建立子连

两端可以通过发送 ADD_ADDR 消息告知对方新的地址,同样可以通过发送 REMOVE_ADDR 删除地址。

在MPTCP会话里,可以通过附带 MPTCP 字段的 SYN 交换来生成 TCP 子流量,MPTCP 字段包含了一个 MP_JOIN 值。MP_JOIN 包含了接收端的哈希共享密钥和原始会话的 token 值,这样两端就能将新生成的 TCP 会话就能和原始会话关联起来了。另外 MP_JOIN 还包含一个随机数,用来防止重发攻击。MP_JOIN 字段包含了发送端的地址,即使地址值被 NAT 转换了,两端还是能获得对方的原始地址。会话两端能在任意端口生成 MP_JOIN 值,也就是说,使用服务器的 80 端口开始会话后,便可以在任意端口对上建立子流量,而服务器无需监听新端口。新的子流量包含:协议、源地址、端口号、目的地址和端口号。

数据发送

数据的传送遵从TCP的传送模式,知识增加了MPTCP字段和拥塞控制。对于某一时间段分别给每条子流发送分配多少数据量由拥赛算法控制(想一下cpu的时间片分配方式),应当是由链路质量决定。

断开

这部分再项目中不是我做的,所以有点迷糊。但是断开的基本方式就是再option中添加断开字段,然后rst所有连接。具体有时间再研究一下吧。

三、LWIP

Light Weight (轻型)IP协议,有无操作系统的支持都可以运行。LwIP实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,它只需十几KB的RAM和40K左右的ROM就可以运行,这使LWIP协议栈适合在低端的嵌入式系统中使用。

实现架构

其实这是接收过程的结构,发送过程中的结构类似就不画了。反正实现很简单。也是看了这个协议栈和BSD的协议栈,对比之下对内核中的协议栈有了比较清楚的理解。

启动:

Lwip在启动时除了初始化一些参数变量,还会启动一个loop线程。线程不断的从mbox中读取消息,取出后进行处理。是不是有些像android中的handler机制的实现。

发送消息:

应用程序调用发送数据的接口时,会像mbox中投递一个消息,消息中带有callback函数,在tcpip线程获取消息时,会调用该回掉函数进行数据传递、发送。

接收消息:

当网络消息发送过来时,网卡设备会对数据进行解析,并调用ip_input函数上报消息给ip层,ip层会遍历所有存在的连接,进而判断是否由本机接收。当找到对应的连接后,会经过传输层解析,数据会被保存到该连接的接收队列中。

当用户调用接口接收数据时,会从自身的socket数据结构中持有的接收队列获取数据。

关于UDP的思考

MPTCP仅仅能解决多tcp的传输问题,对于UDP是无能为力的。但是当下的游戏和流媒体都是UDP基础,接下来的HTTP版本也会逐渐转向UDP。所以考虑一下多UDP的实现应该如何。

目前看来,tcp是面向连接的而UDP是无连接的。所以再双链路激活的情况下应当可以直接通过两个UDP socket使用不同的IP向目标服务器发送数据,再用户层再次对UDP数据进行处理即可,应当没有问题。

如果进行游戏层面的加速,需要再远端提供一个中转服务器,类似迅游或是vpn的方式。将mptcp和UDP的数据进行转发和NAT转换,发往目标服务器。此方式应当是华为之前宣传过的双链路游戏加速功能。