可靠性UDP「译」

Reliable UDP

Posted by decaywood on 2015-12-27
- 错误校对

简介

这篇互联网草案主要讨论可靠性UDP(RUDP)的设计要点。RUDP是一种简单的基于包的传输协议,基于RFCs 1151和908-可靠数据协议,它是建立在UDP/IP层上的协议,并提供可靠有序的(超时重传次数在配置的阈值内)虚连接传输。RUDP具有非常灵活的设计,并且适用于各种使用场景。比如电信信令协议。

背景

可靠性传输协议用于传输基于IP网络的信号,这种可靠性传输必须为应用(例如信令协议)提供一种建立在IP层之上的请求传输。

此协议必须满足下列需求:

  • 传输必须可靠
  • 传输必须有序
  • 传输必须基于消息
  • 传输必须提供相应的流控机制
  • 传输必须低负载高性能
  • 每个虚链接必须可单独配置
  • 传输提供keep-alive机制
  • 传输提供差错检测机制
  • 传输提供相应的安全机制

RUDP每个连接可配置的设计目的在于在相同的平台上仅使用RUDP就可以模拟许多有着不同的传输需求的协议。

数据结构和格式

RUDP首部

RUDP发送的每个UDP包必须以至少6字节的首部(header)开头。第1个字节包含一系列控制标志位,包括SYN/ACK/EACK/RST/NUL/CHK/TCS。接下来5个字节分别为首部长度,序列号(Sequence number),ACK号(Acknowledgment number)以及校验和。


0 1 2 3 4 5 6 7 8              15
+-+-+-+-+-+-+-+-+---------------+
|S|A|E|R|N|C|T| |    Header     |
|Y|C|A|S|U|H|C|0|    Length     |
|N|K|K|T|L|K|S| |               |
+-+-+-+-+-+-+-+-+---------------+
| Sequence #    +  Ack Number   |
+---------------+---------------+
|           Checksum            |
+---------------+---------------+

      Figure 1, RUDP Header 

控制标志位

控制标志位用来标记当前发送的包的类型。SYN表示当前发送的是同步分片;ACK表示当前包首部ACK编号是有效的;EACK表示当前发送的是拓展ACK分片;RST表示当前发送的是重置分片;NUL表示当前发送的是空分片;TCS表示当前发送的是连接状态分片;SYN/ACK/EACK/RST和TCS标志位是互斥的。NUL分片的ACK标志位必须有效。CHK标志位决定了校验和字段是仅计算首部还是整个包的校验和(首部+数据),如果CHK标志位为0,代表仅对首部进行校验,若为1则校验整个包的数据。

首部长度

首部长度字段标记了用户数据从包的哪个位置开始。如果包的总长度超过了首部长度,说明包中有用户数据存在。含有用户数据的包EACK/NULL以及RST标志位不能为1。如果一个包有用户数据,那么首部一定有ACK标记,这种包称为数据分片。

序列号

每个包包含一串序列号。当连接建立,每个对等实体(译者注:连接两端的计算机或其他设备)随机获取一个初始序列号,这个序列号用于SYN分片建立连接。每次传送数据时,程序在发送数据(data)/空(null)或者重置(reset)分片之前对序列号进行自增操作。

ACK编号

ACK编号字段向发送方指明了当前接收方最后成功接收到的一个有序包(失序包稍后介绍)的序列号。

校验和

校验和始终计算RUDP首部来确保完整性。此外,如果CHK标志位设值成1,校验和也可以同时校验数据部分。RUDP使用的校验和算法与UDP/TCP首部中的校验和算法一致,算法为每16位数据位的二进制反码相加然后再进行取反。

SYN分片

SYN分片用于在两个host之间建立连接并同步序列号。SYN分片也包含连接中双方可以交涉的参数,所有对等实体间的可配置参数都包含在这个分片之中。其中包括本地RUDP可接收的最大分片数目和标识了正在建立的连接的一些特征的标志位。SYN分片禁止携带用户数据。SYN分片也可以用于自动复位一个连接,自动复位连接的概念稍后解释。

0              7 8             15
+-+-+-+-+-+-+-+-+---------------+
| |A| | | | | | |               |
|1|C|0|0|0|0|0|0|      28       |
| |K| | | | | | |               |
+-+-+-+-+-+-+-+-+---------------+
+  Sequence #   +  Ack Number   |
+---------------+---------------+
| Vers | Spare  | Max # of Out  |
|      |        | standing Segs |
+---------------+---------------+
| Option Flags  |     Spare     |
+---------------+---------------+
|    Maximum Segment Size       |
+---------------+---------------+
| Retransmission Timeout Value  |
+---------------+---------------+
| Cumulative Ack Timeout Value  |
+---------------+---------------+
|  Null Segment Timeout Value   |
+---------------+---------------+
| Transfer State Timeout Value  |
+---------------+---------------+
| Max Retrans   |  Max Cum Ack  |
+---------------+---------------+
| Max Out of Seq| Max Auto Reset|
+---------------+---------------+
|     Connection Identifier     |
+                               +
|      (32 bits in length)      |
+---------------+---------------+
|           Checksum            |
+---------------+---------------+

     Figure 2, SYN分片

Sequence Number(序列号)

序列号字段包含建立连接时获取的随机初始序列号。

Acknowledgment Number(ACK编号)

这个字段只在ACK标志位设值后有效,如果ACK有效,这个字段将包含从其他RUDP发送方接收到的SYN的序列号。

Version(版本号)

版本字段包含RUDP协议的版本号,初始版本为1.0。

Maximum Number of Outstanding Segments(未完成接收分片最大数量)

这个字段标识了发送队列中接收方未进行回复的分片数量的最大值,此字段被接收方用于流量控制。这个字段必须在连接建立之初指定,在整个连接过程中都不再改变。这个参数不需要双方协调,由接收方给定,接收方在发送方发送数据之前必须提供此参数给发送方。

Options Flag Field(可选标志位字段)

这个字段占两个字节,其中包含一些标志位,标志位用于指定一些请求连接时可选的一些功能,字段留有冗余,标志位定义如下:

Bit Name Description
0 not used 未使用,必须始终设置为1。
1 CHK 这样数据校验和将启用,校验和数据位将包含整个RUDP包的校验和(首部和数据),此数据位为需要收发双方达成一致。
2 REUSE 此标志位用于觉得连接是否重用先前协商的参数,自动复位时此标志位必须设值。当比特为置为1,以下SYN分片字段将被发送方清零,接收方也将忽略这些字段:Maximum Segment Size, Retransmission Timeout Value, Cumulative Ack Timeout Value, Max Retransmissions, Max Cumulative Ack, Max Out of Sequence, and MaxAuto Reset.
3-7 冗余  

Maximum Segment Size(最大分片大小)

这个字段表示发送此SYN的对等实体可接收的最大字节数,每个对等实体参数可能不同,双方发送的包大小必须小于在连接建立时约定好的最大分片大小。此大小包括RUDP首部大小,此字段不是可协商参数,需无条件接受。

Retransmission Timeout Value(重传超时值)

指定重发未进行确认的包的超时阈值,单位为毫秒,有效范围为100到65536.这个参数双方可以交涉,两边参数需要达成一致。

Cumulative Ack Timeout Value(累积ACK超时值)

指定了可以累积收到数据包然后一次性发送ACK的时间阈值。单位为毫秒,有效范围为100到65536.这个参数双方可以交涉,两边参数需要达成一致。此外,此参数必须小于重传超时阈值(Retransmission Timeout Value)。

Null Segment Timeout Value(空分片超时值)

连接空闲时,发送空分片的时间间隔。发送空分片的目的在于心跳机制。此字段单位为毫秒,有效范围为0到65536。0代表不启用心跳机制。这个参数双方可以交涉,两边参数需要达成一致。

Transfer State Timeout Value(传输状态超时值)

这个超时值指定了连接状态信息将保存多久才对连接进行重置。此字段单位为毫秒,有效范围为0到65536。这个参数双方可以交涉,两边参数需要达成一致。0代表连接将立刻进行自动复位。

Max Retrans(最大重传数)

这个值表示被认为连接中断前,进行连续尝试重传的最大次数。有效范围为0到255,0代表将一直尝试进行重传。这个参数双方可以交涉,两边参数需要达成一致。

Max Cum Ack(最大累积ACK数量)

这个值指定了可累积一次性发送的ACK分片的最大数量,有效范围为0到255,0代表当接收到数据(data)/空(null) 或者重置(reset)分片后,ACK将立即发送。这个参数双方可以交涉,两边参数需要达成一致。

Max Out of Seq(最大允许失序包数量)

在拓展ACK(Extended Acknowledgment)发送前,可累积接收的失序(out of sequence)包的最大数目。有效范围为0到255,0代表如果接收到一个非期望顺序的包,EACK将被立即发送。这个参数双方可以交涉,两边参数需要达成一致。

Max Auto Reset(最大复位次数)

在连接被重置前,可执行连续自动复位的最大次数。有效范围为0到255,0代表如果出现需要自动复位的情况时,不会执行自动复位,连接会立即进行重置。这个参数双方可以交涉,两边参数需要达成一致。一旦连接建立,连续自动复位计数器将会被清零。

Connection Identifier(连接ID)

当对等实体建立一个新的连接时,双方会传输一个唯一的连接ID给对方,ID在所有存在的RUDP连接中唯一,每个对等实体会保存接收到的连接ID。当自动复位启动,对等实体将发送连接建立时保存的对方的连接ID来指示当前连接的自动复位操作正在执行。

ACK分片

ACK分片用于对接收到的有序分片进行回应,代表已收到。它的RUDP首部既包含需要接收的下一个分片序列号也包含了已接收的包的序列号。ACK分片虽然可能被作为裸ACK分片(Stand-alone ACK分片)进行发送,但只要有可能,它就应该和数据绑在一起发送。数据和空分片必须始终包含ACK标志位和Acknowledgment序列号字段。裸ACK分片大小为6字节。

0 1 2 3 4 5 6 7 8              15
+-+-+-+-+-+-+-+-+---------------+
|0|1|0|0|0|0|0|0|       6       |
+-+-+-+-+-+-+-+-+---------------+
|  Sequence #   |   Ack Number  |
+---------------+---------------+
|            Checksum           |
+---------------+---------------+

Figure 3, Stand-alone ACK分片

EACK分片

EACK分片用于对失序(out of sequence)的包进行回复。它包含一个或多个接收到的失序包的序列号。EACK分片由ACK分片拓展,并记录接收到的最后一个有序包的序列号,每个EACK包首部长度不固定,包大小最小值为7字节,最大值视最大接收队列长度而定。

0 1 2 3 4 5 6 7 8              15
+-+-+-+-+-+-+-+-+---------------+
|0|1|1|0|0|0|0|0|     N + 6     |
+-+-+-+-+-+-+-+-+---------------+
|  Sequence #   |   Ack Number  |
+---------------+---------------+
|1st out of seq |2nd out of seq |
|  ack number   |   ack number  |
+---------------+---------------+
| . . .         |Nth out of seq |
|               |   ack number  |
+---------------+---------------+
|            Checksum           |
+---------------+---------------+

     Figure 4, EACK分片

RST 分片

RST分片用于关闭或重置连接,当接收到一个RST分片时,发送方必须停止发送新的包,但必须继续尝试发送已从上层接口接收到的包。RST分片作为单独的分片发送,不能包含任何数据。

0 1 2 3 4 5 6 7 8              15
+-+-+-+-+-+-+-+-+---------------+
| |A| | | | | | |               |
|0|C|0|1|0|0|0|0|       6       |
| |K| | | | | | |               |
+-+-+-+-+-+-+-+-+---------------+
|  Sequence #   |   Ack Number  |
+---------------+---------------+
|         Header Checksum       |
+---------------+---------------+

	Figure 5, RST分片

NUL分片

NUL分片用于确定连接是否任然是活跃的,因此,NUL分片承担了keep-alive的任务。当接收到一个NUL分片,在连接存在且收到的分片序列号有序,RUDP就必须立刻返回一个ACK分片,最后NUL分片被丢弃。NUL分片必须含有ACK字段,但绝对不能携带用户数据。

0 1 2 3 4 5 6 7 8              15
+-+-+-+-+-+-+-+-+---------------+
|0|1|0|0|1|0|0|0|       6       |
+-+-+-+-+-+-+-+-+---------------+
|  Sequence #   |   Ack Number  |
+---------------+---------------+
|            Checksum           |
+---------------+---------------+

	Figure 6, NUL 分片

TCS 分片

TCS分片用于传输连接状态信息

0 1 2 3 4 5 6 7 8	           15
+-+-+-+-+-+-+-+-+---------------+
| |A| | | | | | |               |
|0|C|0|0|0|0|1|0|      12       |
| |K| | | | | | |               |
+-+-+-+-+-+-+-+-+---------------+
|   Sequence #  |   Ack Number  |
+---------------+---------------+
| Seq Adj Factor|     Spare     |
+---------------+---------------+
|      Connection Identifier    |
+                               +
|       (32 bits in length)     |
+---------------+---------------+
|           Checksum            |
+---------------+---------------+

       Figure 7, TCS 分片

Sequence Number(序列号)

序列号字段包含了此连接的初始序列号。

Acknowledgment Number(ACK编号)

ACK号字段代表已接收方已接收到的最后一个有序包的序列号。

Seq Adj Factor(序列号校正因子)

这个字段用于在当前连接与上一次连接之间传输状态信息由此校正序列号。

Connection Identifier(连接ID)

当对等实体建立一个新的连接时,传输一个唯一的连接ID,ID在所有存在的RUDP连接中唯一。每个对等实体保存接收到的连接ID。这个字段用于把正在传送到当前连接的连接记录信息通知给对等的连接。

Feature Description(特性介绍)

RUDP支持以下特性,在介绍之前先定义一些概念,发送方与接收方既可以指客户端也可以指服务器,它们分别用于发送和接收数据分片。客户端代表初始化连接的对等实体,服务器代表监听连接的对等实体。连接定义为一个服务于一对有唯一IP地址和UDP端口的对等实体的接口。服务器和客户端在一个特定IP和端口上可以拥有多个连接。每个连接只能存在于唯一的一对IP和端口上。

1. Retransmission Timer(重传定时器)

发送方有一个可配置超时时间的重传定时器,每当数据(data)/空(null)或者重置(reset)分片发送且没有分片被计时,计时器将被初始化。如果数据分片的ACK在规定时间内没被接收,计时器超时,所有已发送但没接收到ACK的分片将被重新发送。当某个计时分片接收到ACK,但仍然有一个或多个已发送包没收到ACK,计时器将重新开始计时。推荐的重发计时器值为600毫秒。

2. Retransmission Counter(重传计数器)

发送方维护着一个对分片重传次数计数的计数器,计数器的计数最大值是可配置的,推荐值为2。如果计数值超过了最大值,连接将被视为中断,在14条将会解释RUDP是如何处理连接中断的。

3. Stand-alone acknowledgments(裸ACK分片)

裸ACK分片只包含ACK信息,其序列号字段包含下一个将要发送的数据(data)/空(null)或者重置(reset)分片的序列号。

4. Piggyback acknowledgments(ACK信息捎带)

接收者发送数据(data)/空(null)或者重置(reset)分片给发送者时,无论何种情况,接收者必须将从发送者那接收到的最后一个有序数据(data)/空(null)或者重置(reset)分片的序列号包含在将被接收者发送的分片首部的ACK编号字段中。

5. Cumulative acknowledge counter(累积ACK分片计数器)

接收者维护了一个Unacknowledged分片计数器(以便发送数据分片或其他分片时进行ACK捎带),Unacknowledged分片指已接收到但还未发送ACK分片给发送者的分片。计数器最大值可配置,如果超过计数器最大值,接收者可以发送stand-alone ACK分片,如果当前接收到失序分片,也可以发送拓展ACK分片。计数器参数推荐设值为3。

6. Out-of-sequence acknowledgments counter(失序ACK计数器)

接收者维护了一个统计接收到的失序分片数量的计数器,每当计数器超过了它配置的最大值,接收者将发送一个拓展ACK(extended acknowledgment)分片,然后将计数器归零。拓展分片包含了当前所有接收到的失序分片的序列号。计数器参数推荐设值为3。

当发送方接收到一个拓展ACK分片,将重传丢失的数据分片给接收方。

7. Cumulative acknowledge timer(累积ACK分片计时器)

当接收者有任何还未发送确认ACK的分片或者失序队列中存在分片,在发送对应裸ACK或拓展ACK之前,指定时间内,接收者会进行等待。当计时器超时,如果失序队列中仍然有分片存在,接收者将发送拓展ACK,否则为未发送ACK分片的包发送裸ACK。Cumulative acknowledge timer推荐值为300毫秒。

假如当前失序队列没有分片存在,无论ACK是以捎带还是裸ACK形式发送出去的,累积ACK计时器都会重启,否则继续计时以等待超时后发送拓展ACK。

8. Null Segment timer(空分片计时器)

客户端维护了一个空分片计时器,此计时器在连接建立后开始计时,每当数据包发送后便对其复位,如果客户端的空分片计时器超时,客户端将发送空分片给服务器。如果空分片序列号有效,服务器会对空分片进行ACK回应。服务器同样维护了一个空分片计时器,此超时值是客户端配置值的两倍,只要从客户端接收到数据分片或者空分片,服务端将计时器复位。如果计时器超时,服务器断定连接中断,在14条将会解释RUDP是如何处理中断连接的。空分片计时器推荐值为2秒。

9. Auto Reset(自动复位)

连接的两边都可能发动连接自动复位,重传计数超过最大值/服务器空分片计时器超时或者传输状态计时器超时,都可能触发自动复位。自动复位将导致连接的两端重置它们当前的状态信息,包括:刷新重发和失序队列,重设它们的初始序列号,重新协调连接参数。连接的两端将通知上层协议(Upper Layer Protocol – ULP)自动复位。在连接断开的情况下,连续复位计数器在计数状态,由于配置了阈值,如果计数器超过了其最大值,连接将被重置。连续重置计数器推荐设置为3。

10. Receiver Input Queue Size(接收者接受队列大小)

接收者接收队列大小是可配置的参数,推荐大小为32个包,接收队列大小为流控机制的一部分。

11. Congestion control and slow start(拥塞控制和延迟启动)

RUDP并没有提供任何拥塞控制或者延迟启动算法。

12. UDP port numbers(UDP端口号)

RUDP没对UDP端口的使用做任何限制,除了RFC 1700定义的端口其他都为可用端口。

13. Support for redundant connections(支持冗余连接)

如果RUDP连接失败,RUDP会告知上层协议,且转移状态计时器启动,上层协议可以通过调用API来启动当前连接到新连接的状态转移,RUDP将转移状态信息到新的连接并保证包不会重复发送或者漏发。如果上层协议在状态转移计时器超时之前没有成功转移状态到新的连接,连接状态将会丢失,连接队列缓冲区将被释放。转移状态计时器超时值是可配置的,推荐值为1秒。

14. Broken connection handling(连接中断的处理)

如果出现以下两种情况的任何一种,RUDP连接将被视为中断:

  • 重发计时器超时且重发计数器超过配置的最大值
  • 服务器空分片计时器超时(keep-alive失效)

以上任意一种情况出现且转移状态超时值为非零,RUDP将发送公共接口的连接失败信号通知上层协议,同时转移状态计时器启动。如果转移状态计时器超时,自动复位启动,RUDP发送公共接口的连接自动复位信号通知上层协议。

如果转移状态超时值设为0,自动复位将在以上两种情况出现时被立即执行,RUDP发送连接自动复位信号通知上层协议。

15. Retransmission Algorithm(重传算法)

包重传发生在接收到拓展ACK分片或重传计时器超时的情况下,当接收到拓展分片时,拓展ACK分片中包含了未被接收者接收到的分片序列号,对应的分片将从unacknowledged发送队列中移除并重新发送,需要重新发送的分片通过检测拓展分片中的ACK编号和最后一个失序ACK编号确定。unacknowledged队列中所有在这之间但不包括这两个序列号的对应分片必须重新发送。

当重传超时时,所有存储在unacknowledged发送队列的消息都将被重新发送。

16. Signals to Upper Layer Protocol (上层协议通信信号)

以下信号将通过接口传输给上层协议,用于向上层协议通知异步事件:

  • Connection Open - 当连接状态转为连接建立时发送
  • Connection Refused - 连接状态转为从非关闭等待状态转为关闭状态时发送
  • Connection Closed - 连接状态从关闭等待状态转为关闭状态时发送
  • Connection Failure - 当连接声明为断开时(Feature Description)发送
  • Connection auto reset - 当连接自动复位时发送。这将向上层协议通知数据可能丢失或者RUDP正在尝试使连接转为连接建立状态

17. Checksum Algorithm

RUDP使用的校验和算法和UDP以及TCP首部使用的校验和算法相同,算法为每16位数据位的二进制反码相加然后再进行取反。如果在建立连接时协商好,校验和将计算整个RUDP包的数据。算法通过在建立连接的SYN分片中设值CHK标志位来配置。否则校验和只计算RUDP首部,算法具体实现请参考RFC 1071

18. FEC(前向纠错)

RUDP没有定义前向纠错(FEC),故RUDP通过产生重发来兼容,如果包出错,将不会回复ACK,发送方将进行重传,直至收到正确的数据。

Feature Negotiation(配置参数协商)

当客户端初始化连接时,它发送SYN分片,分片包含由上层协议通过接口定义的可协商的参数。服务器可以通过向SYN分片回应相应的ACK来表示接受这些参数配置,否则修改SYN分片并设置ACK标志位并回复。客户端同样通过发送ACK来选择接受SYN中的参数来建立连接否则发送一个RST来拒绝连接。可协商参数不能在自动复位的时候进行重新协商。

Future Potential Enhancements(未来的改良空间)

除了客户端/服务器模式之外,RUDP支持对称的操作模式,这将允许两边动态地建立连接。RUDP支持序列号和ACK字段由现在的1字节拓展到2字节。这将允许传输窗口的大小超过255。