udp如何实现可靠性传输?

一、udp 与 tcp 的区别:

TCP(TransmissionControl Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

UDP 是 User Datagram Protocol,一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。可靠性由上层应用实现,所以要实现 udp 可靠性传输,必须通过应用层来实现和控制

二、TCP 如何实现可靠性传输:

可靠性:

  • 应用数据被分割成 TCP 认为最适合发送的数据块。这和 UDP 完全不同,应用程序产生的数据长度将保持不变。由 TCP 传递给 IP 的信息单位称为报文段或段(segment)。

  • 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认。TCP 有延迟确认的功能,在此功能没有打开,则是立即确认。功能打开,则由定时器触发确认时间点。

  • TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。

  • 既然 TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TCP 报文段的到达也可能会失序。如果必要,TCP 将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。

  • 既然 IP 数据报会发生重复,TCP 的接收端必须丢弃重复的数据。

  • TCP 还能提供流量控制。TCP 连接的每一方都有固定大小的缓冲空间。TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

重传策略:

TCP 协议用于控制数据段是否需要重传的依据是设立重发定时器。在发送一个数据段的同时启动一个重传,如果在重传超时前收到确认 (Acknowlegement) 就关闭该重传,如果重传超时前没有收到确认,则重传该数据段。在选择重发时间的过程中,TCP 必须具有自适应性。它需要根据互联网当时的通信情况,给出合适的重发时间。

这种重传策略的关键是对定时器初值的设定。采用较多的算法是 Jacobson 于 1988 年提出的一种不断调整超时时间间隔的动态算法。其工作原理是:对每条连接 TCP 都保持一个变量 RTT(Round Trip Time),用于存放当前到目的端往返所需要时间最接近的估计值。当发送一个数据段时,同时启动连接的定时器,如果在定时器超时前确认到达,则记录所需要的时间(M),并修正 [2]  RTT 的值,如果定时器超时前没有收到确认,则将 RTT 的值增加 1 倍。通过测量一系列的 RTT(往返时间)值,TCP 协议可以估算数据包重发前需要等待的时间。在估计该连接所需的当前延迟时通常利用一些统计学的原理和算法(如 Karn 算法),从而得到 TCP 重发之前需要等待的时间值。

窗口确认:

TCP 的一项功能就是确保每个数据段都能到达目的地。位于目的主机的 TCP 服务对接受到的数据进行确认,并向源应用程序发送确认信息。使用数据报头序列号以及确认号来确认已收到包含在数据段的相关的数据字节。

TCP 在发回源设备的数据段中使用确认号,指示接收设备期待接收的下一字节。这个过程称为期待确认。

源主机在收到确认消息之前可以传输的数据的大小称为窗口大小。用于管理丢失数据和流量控制。

三、udp 如何实现可靠性传输:

UDP 它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用 UDP 较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

  • 传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照 tcp 可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。

  • 实现确认机制、重传机制、窗口确认机制。

  • 如果你不利用 Linux 协议栈以及上层 socket 机制,自己通过抓包和发包的方式去实现可靠性传输,那么必须实现如下功能:

  • 发送:包的分片、包确认、包的重发

  • 接收:包的调序、包的序号确认

  • 目前有如下开源程序利用 udp 实现了可靠的数据传输。分别为 RUDP、RTP、UDT。

RUDP:

RUDP 提供一组数据服务质量增强机制,如拥塞控制的改进、重发机制及淡化服务器算法等,从而在包丢失和网络拥塞的情况下, RTP 客户机(实时位置)面前呈现的就是一个高质量的 RTP 流。在不干扰协议的实时特性的同时,可靠 UDP 的拥塞控制机制允许 TCP 方式下的流控制行为。

RTP:

实时传输协议(RTP)为数据提供了具有实时特征的端对端传送服务,如在组播或单播网络服务下的交互式视频音频或模拟数据。应用程序通常在 UDP 上运行 RTP 以便使用其多路结点和校验服务;这两种协议都提供了传输层协议的功能。但是 RTP 可以与其它适合的底层网络或传输协议一起使用。如果底层网络提供组播方式,那么 RTP 可以使用该组播表传输数据到多个目的地。

RTP 本身并没有提供按时发送机制或其它服务质量(QoS)保证,它依赖于底层服务去实现这一过程。RTP 并不保证传送或防止无序传送,也不确定底层网络的可靠性。RTP 实行有序传送, RTP 中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,例如:在视频解码中,就不需要顺序解码。

UDT:

基于 UDP 的数据传输协议(UDP-basedData Transfer Protocol,简称 UDT)是一种互联网数据传输协议。UDT 的主要目的是支持高速广域网上的海量数据传输,而互联网上的标准数据传输协议 TCP 在高带宽长距离网络上性能很差。顾名思义,UDT 建于 UDP 之上,并引入新的拥塞控制和数据可靠性控制机制。UDT 是面向连接的双向的应用层协议。它同时支持可靠的数据流传输和部分可靠的数据报传输。由于 UDT 完全在 UDP 上实现,它也可以应用在除了高速数据传输之外的其它应用领域,例如点到点技术(P2P),防火墙穿透,多媒体数据传输等等。

因项目中的需要,现在详细分析一下 UDT 是如何通过 udp 实现数据的可靠传输。通过阅读源码的方式。

四、UDT 原理分析:

主要通过分析源码来弄清楚如何利用 udp 实现数据的可靠性传输,主要按照协议格式、关键数据结构等展开。

UDT 应用层协议:

UDT 并不是在瓶劲带宽相对较小的和大量多元短文档流的情况下用来取代 TCP 的。

UDT 主要作为 TCP 的朋友,和 TCP 并存,UDT 分配的带宽不应该超过根据 MAX-MIN 规则的最大最小公平共享原则。(备注,最大最小规则允许 UDT 在高 BDP 连接下分配 TCP 不能使用的可用带宽)。

UDT 是双工的,每个 UDT 实体有两个部分:发送和接收。

发送者根据流量控制和速率控制来发送(和重传)应用程式数据。

接收者接收数据包和控制包,并根据接收到的包发送控制包。发送和接收程式共享同一个 UDP 端口来发送和接收。

接收者也负责触发和处理任何的控制事件,包括拥塞控制和可靠性控制和他们的相对机制,例如 RTT 估计、带宽估计、应答和重传。

UDT 总是试着将应用层数据打包成固定的大小,除非数据不够这么大。和 TCP 相似的是,这个固定的包大小叫做 MSS(最大包大小)。由于期望 UDT 用来传输大块数据流,我们假定只有很小的一部分不规则的大小的包在 UDT session 中。MSS 能够通过应用程式来安装,MTU 是其最优值(包括任何包头)。

UDT 拥塞控制算法将速率控制和窗口(流量控制)合并起来,前者调整包的发送周期,后者限制最大的位被应答的包。在速率控制中使用的参数通过带宽估计技术来更新,他继承来自基于接收的包方法。同时,速率控制周期是估计 RTT 的常量,流控制参数依赖于对方的数据到达速度,另外接收端释放的缓冲区的大小。

报文类型及格式:

UDT 有两种包:数据包和控制包。他们通过包头的第一位来区分(标志位)。如果是 0,表示是数据包,1 表示是控制包。

数据包:

数据包结构如下显示:

包序号是 UDT 数据包头中唯一的内容。它是一个无符号整数,使用标志位后的 31 位,UDT 使用包基础的需要,例如,每个非重传的包都增加序号 1。序号在到达最大值 2^31-1 的时候覆盖。紧跟在这些数据后面的是应用程序数据。

控制包:

控制包结构如下:

有 6 种类型的控制包在 UDT 中,bit1-3 表示这些信息。前 32 位在包头中必须存在。控制信息字段包括 0(例如,它不存在)或者多个 32 位无符号整数,这由包类型决定。

UDT 使用应答子序号的方法。每个 ACK/ACK2 包有一个无符号的 16 位序号,它独立于数据包需要。它使用位 16-31。应答需要从 0 到(2^16-1)。位 16-31 在其他控制包中没有定义。

注意,对于数据和控制包来说,可以从 UDP 协议头中得到实际的包大小。包大小信息能被用来得到有效的数据负载和 NAK 包中的控制信息字段大小。

定时器:

UDT 在接收端使用 4 个定时器来触发不同的周期事件,包括速率控制、应答、丢失报告(negative 应答)和重传 / 连接维护。

UDT 中的定时器使用系统时间作为源。UDT 接收端主动查询系统时间来检查一个定时器是否过期。对于某个定时器 T 来说,其拥有周期 TP,将定变量 t 用来记录最近 T 被设置或复位的时间。如果 T 在系统时间 t0(t= t0)被复位,那么任何 t1(t1-t>=TP)是 T 过期的条件。

四个定时器是:RC 定时器、ACK 定时器、NAK 定时器、EXP 定时器。他们的周期分别是:RCTP、ATP、NTP、ETP。

RC 定时器用来触发周期性的速率控制。ACK 定时器用来触发周期性的有选择的应答(应答包)。RCTP 和 ATP 是常量值,值为:RCTP=ATP=0.01 秒。

NAK 被用来触发 negative 应答(NAK 包)。重传定时器被用来触发一个数据包的重传和维护连接状态。他们周期依赖于对于 RTT 的估计。ETP 值也依赖于连续 EXP 时间溢出的次数。推荐的 RTT 初始值是 0.1 秒,而 NTP 和 ETP 的初始值是:NTP=3_RTT,ETP=3_RTT+ATP。

在每次 bounded UDP 接收操作(如果收到一个 UDP 包,一些额外的必须的数据处理时间)时查询系统时间来检查四个定时器是否已经过期。推荐的周期粒度是微秒。UDP 接收时间溢出值是实现的一个选择,这依赖于循环查询的负担和事件周期精确度之间的权衡。

速率控制事件更新包发送周期,UDT 发送端使用 STP 来安排数据包的发送。假定一个在时间 t0 被发送,那么下一次包发送时间是(t0+ STP)。换句话说,如果前面的包发送花费了 t’时间,发送端将等待(STP-t’)来发送下一个数据包(如果 STP-t’ <0,就不需要等待了)。这个等待间隔需要一个高精确度的实现,推荐使用 CPU 时钟周期粒度。

最简单的方式是在应用层模仿传输层 TCP 的可靠性传输。下面不考虑拥塞处理,谈谈自己的个人简单粗暴的设计:

  • 1、添加 seq/ack 机制,确保数据发送到对端。

  • 2、添加发送和接收缓冲区,主要是用户超时重传。

  • 3、添加超时重传机制。

发送端发送数据时,生成一个随机 seq=x,然后每一片按照数据大小分配 seq。数据到达接收端后接收端放入缓存,并发送一个 ack=x 的包,表示对方已经收到了数据。发送端收到了 ack 包后,删除缓冲区对应的数据。

时间到后,定时任务检查是否需要重传数据。

如下是 tcp 的确认机制

开源项目:

https://github.com/caozhiyi/Hudp


文章来源:

https://www.cnblogs.com/ostin/p/6863240.html

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐