基于 UDP 的协议 (UDT) 是一种高性能数据传输协议。用于广域高速网络上的分布式数据密集型应用程序。 UDT 使用 UDP 传输具有自己的可靠性控制和拥塞控制机制的批量数据。 新协议可以以比 TCP 高得多的速度传输数据。 UDT 也是一个高度可配置的框架,可以适应各种拥塞控制算法。
为什么需要使用UDT?
UDT 的最初(和主要)目的是为广域网上的分布式数据密集型应用程序提供高性能传输接口,因为效率和公平原因,TCP 很少能很好地工作。它也可以用于 TCP 不适合的其他情况(例如,多媒体流、防火墙穿孔、部分可靠性等)
没有明确的标准来确定何时使用 UDT 或何时不使用。一般来说,如果对 TCP 的性能或功能不满意,UDT 可能是你所需要的,尤其是在少量批量源共享丰富带宽的高速网络中。
UDT数据包
UDT有两种包:数据包和控制包;数据包。 它们通过第 1 位(标志位)来区分包头。
数据包头从 0 开始。包序号使用标志位之后的 31 位。 UDT 使用基于数据包的排序,即每发送一次,序列号加1数据包按照包发送的顺序。序号是将其增加到最大数量 (2^31 - 1) 后进行包装。
数据包头结构如下:
以上是发送数据包时的 32 位时间戳和目标套接字 ID。时间戳是一个相对值开始。
UDT控制包和类型信息
UDT中有8种类型的控制包和类型信息被放在标题的位域 1 - 15 中。 内容以下字段取决于数据包类型。 前 128 位必须存在于数据包头中,而可能存在空控件信息字段,取决于数据包类型。
特别是,UDT 对 ACK 数据包使用子序列。 每个 ACK 包被分配一个唯一递增的 16 位序列号,即与数据包序号无关。 ACK序列number 使用控制数据包中的第 32 - 63 位。 ACK 序列号范围从 0 到 (2^31 - 1)。
协议连接握手
握手包有如下信息(假设UDT 套接字 A 将此握手发送给 B):
Version: 32 位,UDT 版本。
Type:32 位,套接字类型(STREAM 或 DGRAM)。
Initial Sequence Number:32位,初始包序号。
MTU:32 位,最大数据包大小(包括 UDP/IP 标头)。
Flow Window:32位,最大流窗口大小。
Requested Type: 32 位,连接类型(常规或集合) 。
ID:32位,套接字ID。
SYN cookie:32 位,SYN cookie。
Peer IP Address:128位,对端UDP套接字的IP地址 。
当服务器第一次收到客户端的连接请求时,它根据客户端地址和一个密钥并将其发送回客户端。然后客户端必须发送将相同的 cookie 返回到服务器。
服务器在收到握手包和正确的cookie时,将数据包大小和最大窗口大小与其自己的值进行比较并将其自己的值设置为较小的值。
来自客户端的连接类型应设置为 1。
来自服务器的响应应设置为 -1
保持活动状态
在收到 ACK 数据包时:更新最大的确认序列号。 在这个ACK中发回一个ACK序列号相同的ACK2。更新 RTT 和 RTTVar。将 ACK 和 NAK 周期都更新为 4 * RTT + RTTVar + SYN。 更新流窗口大小、更新估计的链路容量、更新发送者的缓冲区、更新发件人的丢失列表。
Ack Squence Number:32 bits,所有数据包的序号以前的数据包已经收到。
RTT (microseconds):32 位,RTT(以微秒为单位)。
RTT Variance (microseconds):32位,RTT方差。
Buffer Available (packets):32位,可用缓冲区大小(以字节为单位)。
Rate (packets/second):32 位:数据包接收率(以数据包数量计/ 每秒)。
Link Capacity (packets/second):32 位,估计的链路容量(以数据包数计/每秒) 。
否定确认 (NAK)
在收到 NAK 数据包时:将 NAK 中携带的所有序列号添加到发送者的损失中列表。
Missing Sequence Number:32位压缩丢失信息的整数数组。
关机
如果其中一个连接的 UDT 实体正在关闭,它将发送一个关闭消息给对端。对端,收到此信息后
消息,也将被关闭。
此关闭消息,使用 UDP,只发送一次,不保证能收到。
确认(ACK2)
在收到 ACK2 数据包时: 在 ACK History Window 中根据 此 ACK2 中的 ACK 序列号。更新已确认的最大 ACK 号。根据ACK2到达时间和ACK计算新的rtt出发时间。
UDT协议解析C/C++代码实现
static void dissect_udt(u_char *udt_data, int offset, int Payload_len)
{
udt_conv = (udt_conversation *)malloc(sizeof(udt_conversation));
if (udt_conv == NULL)
{
return ;
}
if (dissect_udt_heur(udt_data, offset, Payload_len))
return ;
if (is_control)
{
const char *typestr = val_to_str(type, udt_packet_types);
switch (type)
{
case UDT_PACKET_TYPE_ACK:
...
break;
case UDT_PACKET_TYPE_ACK2:
...
break;
case UDT_PACKET_TYPE_NAK:
{
unsigned int max = Payload_len;
if (max > UDT_MAX_NAK_LENGTH)
max = UDT_MAX_NAK_LENGTH;
for (i = UDT_CONTROL_OFFSET; i <= (max-4) ; i = i + 4)
{
uint32_t start, finish;
int is_range;
is_range = ntohl(*(uint32_t*)(udt_data + offset + i)) & 0x80000000;
start = get_sqn(udt_conv, ntohl(*(uint32_t*)(udt_data + offset + i)) & 0x7fffffff);
if (is_range)
{
if (i > (max-8))
{
...
break;
}
finish = get_sqn(udt_conv, ntohl(*(uint32_t*)(udt_data + offset + i + 4)) & 0x7fffffff);
...
i = i + 4;
}
else
{
...
}
}
...
break;
}
default:
...
break;
}
}
else
{
...
}
运行结果:
总结
UDT是一种高性能数据传输协议。它专为通过高速广域网 (WAN) 大量传输大型数据集而设计。基于 UDP 的协议是 TCP 协议的一种更有效的替代方案,并且可以以更高的速度传输数据。
欢迎关注微信公众号【程序猿编码】,需要UDT协议解析完整源码的添加本人微信号(c17865354792)
参考:http://tools.ietf.org/search/draft-gg-udt-03