37、Internet传输协议之UDP(传输层)

引言

  • Internet传输层主要有两个协议,无连接和面向连接各一个,互为补充。无连接协议是UDP,它除了给应用程序提供发送数据包功能并允许它们在所需层次之上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的协议是TCP,该协议几乎做了所有的事情。它建立连接,并通过重传机制增加了可靠性,同时还进行流量控制和拥塞控制,代表使用它的应用程序做了所有的一切。
  • UDP是最简单的传输协议。由于UDP是传输层协议,通常运行在操作系统中二使用UDP的协议通常运行在用户空间,因而可以把对UDP的使用视作应用程序。然而,它们的使用技术对许多应用都有用,而且把这些技术视作属于传输层更好。

1、UDP概述

  • Internet协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP)。UDP为应用程序提供了一种无需建立连接就可以发送封装的IP数据报方法。RFC 768描述了UDP。
  • UDP传输的段由8字节的头和有效载荷字段构成。下图描述了头信息。两个端口分别用来标识源机器和目标机器内部的端点。当一个UDP数据包到来时,它的有效载荷被递交给与目标端口相关联的那个进程。在调用了BIND原语或者其他类似的原语之后,这种关联就建立起来了。可以把端口看做应用程序租来接收数据包的邮箱。实际上,采用UDP而不是原始IP的最主要价值在于增加了源端口和目标端口。如果没有端口字段,传输层将无从知道如何处理每个入境数据包;有了端口之后,它就能把内嵌的段递交给正切的应用程序处理。在这里插入图片描述
  • 当接收段必须将一个应答返回给源端时,源端口字段则是必需的。只要将入境字段中的源端口字段复制到出境段中的目标端口字段。UDP长度字段包含8个字节的头和数据两部分的总长度。最小长度是8个字节,最大长度是65 515字节,恰好低于填满16比特的最大字节数,而这是由IP数据包限制的。一个可选的校检和字段还提供了额外的可靠性。它校检头、数据和一个概念性的IP伪头。执行校检和计算时,校检和字段先被设置为0,如果数据字段的长度是奇数则用0填充成偶字节。校检和算法很简单,先按16位字的补码相加求和,然后再取总和的补码。因此,当接收端对整个段计算校检和时,要包括UDP校检和字段,正确的结果应该为0。如果发送端没有计算校检和,则将该字段值填为0,因为补码计算结果可能碰巧真是0,则储存为全1。然而,关闭校检和计算并不是明智之举,除非数据传输的质量并不重要(如数字化语音)。
  • IPv4的伪头部分如图所示,它包含源机器和目标机器的32位IP地址、UDP的协议号(17),以及UDP段(包括头)的字节计数。IPv6的伪头与其类似。在UDP校检和计算中包含伪头将有助于检测出被错误递交的数据包,但是传输层在计算校检和时需要地址的做法违反了协议分层原则,因为IP地址属于IP层,而不属于UDP层。TCP在计算校检和的时候也使用了统一的伪头。在这里插入图片描述
  • 或许值得明确一提的UDP没有做的事情。它没有流量控制、拥塞控制,或者接收到一个坏段后的重传机制。所有这一切都必须由用户进程来完成。它只是提供了一个与IP协议的接口,并在此接口上增加通过端口号复用多个进程的功能,以及可选的端到端检测功能。这就是UDP所做的一切。对于需要对数据包流实施精确控制、错误检测或者时序功能的应用,UDP提供的服务恰到好处。UDP协议特别有用的一个领域是客户机-服务器应用开发。一般情况下,客户端向服务器发送一个简短的请求报文,并期待来自服务器的简短报文。如果请求或回复报文丢失,客户端就会超时,然后再试一次。以UDP实现的代码相比需要初始建立连接的协议(比如TCP)不仅代码简单,而且需要交换的报文也很少(对于连接来说,每个方向都需要一份)。以这种方式使用UDP的一个应用是域名系统(DNS),简单地说,如果一个应用程序需要查询某个主机的IP地址,比如www.cs.berkeley.edu,那么它可以给DNS服务器发送一个包含该主机名的UDP数据包。服务器用一个包含了该主机IP地址的UDP数据包作为应答。事先不需要建立连接,事后也不需要释放连接。

2、远程过程调用

  • 在某种意义上,向一台远程主机发送一个消息并获得一个应答,就如同在编程语言中执行一个函数调用一样。在这两种情形下,启动时都需要一个或者多个参数,然后获得一个结果。这个领域中关键工作由Birrell和Nelson完成,他们建议允许本地程序调用远程主机上的过程。当机器1上的进程调用机器2上的一个过程,机器1上的调用进程被挂起,而机器2上的被调用过程则开始执行。信息以参数的形式从调用方传输到被调用方,而过程的执行结果则从反方向传递回来。这项技术称为远程过程调用(RPC),目前已经成为许多网络应用的基础。传统式,调用过程称为客户,被调用过程称为服务器。
  • RPC背后的思想是尽可能地使一个远程过程调用看起来像本地过程调用一样。在最简单的形式中,为了调用一个远程过程,客户程序必须绑定(链接)到一个小的库过程,这个库过程称为客户存根,它代表了客户地址空间中的服务器过程。类似地,服务器需要绑定一个称为服务器存根的过程。正是这些过程隐藏了客户机不在本地调用服务器的事实。
  • 图中给出了执行RPC的实际步骤。第一步是客户调用客户存根。这是一个本地过程调用,其参数按照常规方式压入栈中。第二步,客户存根将参数封装到一个消息中,然后通过系统调用发送该消息。封装参数的过程称为列集。第三步,操作系统将消息从客户机发送到服务器上。第四步,操作系统将入境数据包传递给服务器存根。最后服务器存根利用散集得到的参数调用服务器过程。调用的结果沿着相反的方向按相同的路径传递。在这里插入图片描述
  • 这里需要注意的关键点是用户编写的客户过程只是按照普通过程调用的方式来调用客户存根,而且客户存根与服务器过程有相同的名字。由于客户过程和客户存根在同一的地址空间中,所以参数的传递也是按通常的方式进行。类似的,服务器过程被同一地址空间中的一个过程调用,并且它接收到的也正好是它所期望的参数。按照这种方式,网络通信并不是在套接字上完成输入和输出,而是通过仿造一个普通的过程调用来完成的。
  • RFC有一些陷阱,最大的陷阱是指针参数的用法。在正常情况下,将指针传递给一个过程不是问题。被调用过程可以像调用方那样使用这个指针,因为双方生存在相同的虚拟地址空间中。而对于RFC,传递指针是不可能的,因为客户和服务器不再同一地址空间中。在有些情况下,可以使用一些技巧来实现指针的传递。假设第一个参数是一个指向某个整数K的指针,客户存根可以对K进行列集,并发送给服务器;然后,服务器存根创建一个指向k的指针,并且将该指针传递给服务器过程,而这正是服务器过程所期望的。当服务器过程将控制权返回给服务器存根时,后者将K送回客户。在客户端,新的K值被复制到旧的K中,就好像服务器对它做了修改一样。实际上,整个过程相当于用复制、恢复调用代替了按引用调用的标准调用序列。不过,如果指针指向一个图形或者其他复杂的数据结构,这种方式就难以工作了。所以对于远程调用的参数必须强加一些限制。
  • 第二个问题是在一些弱类型的语言中(比如C),编写一个计算两个矢量(即数组)内积,但不指定矢量大小的过程是完全合法的。每个矢量都有一个专门的值作为终止标记,而且该终止值只有调用过程和被调用过程才知道。在这种情况下,客户存根想要对参数执行列集操作从本质上讲是不可能的:无从知道该如何确定参数的长度。
  • 第三个问题在于并不总是能推断出参数的类型,即使从正式的规范或者代码本身都未必能做得到。一个例子是printf,它可能有多个参数,而且这些参数可以是整数、长整数、字符、字符串、可变长度的浮点数和其他类型的任意组合。试图以远程调用的过程来调用printf不太现实,因为C语言对类型的要求特别宽松。然而有一条法则是这样的:只要不用C(或者C++)编写程序,那么就可以使用RPC,但这样的说法没有得到程序员的认可。
  • 第四个问题设计全局变量的使用。正常情况下,调用过程和被调用过程除了通过参数进行通信外,也可以使用全局变量作为通信的手段。如果被调用的过程转移到了远程机器上,那么这样的代码就会失败,因为全局变量无法再为双方共享。这些问题并不意味着RPC就没有希望。事实上,它的应用仍然十分广泛,凡是在实际运用中,需要有一些限制才能保证它正常工作。
  • 关于传输层协议,UDP是一个实现RPC的良好基础。请求和应答可作为单个UDP数据包以简单的形式发送,并且可以快速进行操作。然而,RPC的实现必须包括其他机器。因为请求或应答数据包可能会丢失,客户端必须维持一个计时器用来重发请求。请注意,应答数据包可当做一个请求的隐含确认,因此该请求不再需要单独确认。某些时候,参数或结果可能大于最大的UDP数据包大小,在这种情况下需要传递大块消息的某种协议。如果多个请求和应答可以重叠(并发编程情况下),则需要一个标识符把应答和请求相匹配。
  • 一个更高层次的关注是操作可能不是幂等的(即重复安全。在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同)。一个简单的幂等操作例子是DNS请求和应答。客户如果没有收到答复,可以放心地一次又一次重发请求,无需担心服务器是否永远收不到请求,或者返回的应答报文会丢失。当应答报文终于来临,答案将是相同的(DNS在此期间没有更新)。然而,并非所有的操作都是幂等的,因为它们有重复的副作用,比如递增一个计数器。对于这些非幂等操作RPC需要较强的语义,以便当程序员调用一个过程时它不会被多次执行。在这种情况下,可能有必要建立一个TCP连接并在连接上发送请求,而不是使用UDP发送请求报文。

3、实时传输协议

  • 客户-服务器RPC是UDP被广泛应用的一个领域,UDP的另一应用是实时多媒体应用。尤其是,随着Internet广播电台、Internet电话、音乐点播、视频会议、视频点播和其他多媒体应用越来越普及,人们发现每一种应用都在或多或少地重复设计几乎相同的实时传输协议。逐渐地人们认识到,为多媒体应用定制一个通用的实时传输协议是一种很好的想法。于是实时传输协议(RTP)诞生了。RTP由RFC 3550描述,目前已经广泛应用于多媒体应用程序。我们将描述实时传输的两个方面。第一个是RTP协议,它以数据包形式传输音频和视频数据。第二个主要是接收端的处理,涉及在正确的时间播放音频和视频。这些功能在协议栈中的位置如图。在这里插入图片描述
  • RTP通常运行在用户空间,位于UDP之上。它的操作方式如下所述。多媒体应用由多个音频、视频、文本或可能的其他流组成。这些流被送入到RTP库中,RTP库和多媒体应用一起都都位于用户空间。然后,RTP库将这些流复用并编码到RTP数据包中,RTP数据包再被塞到一个套接字中。在套接字的操作系统那一端,RTP数据包被封装到新生的UDP数据包,这些UDP数据包被交给IP,以便发送到链路上,比如以太网。在接收端的处理和发送端的处理次序相反。最终多媒体应用从RTP库函数接收到多媒体数据,它负责播放所收到的媒体。这种情况的协议栈如图a所示。数据包的嵌套如图b。
  • 这种设计的后果是很难说清RTP位于哪一层。由于它运行在用户空间,并且与应用程序链接,所以它无疑看起来像是一个应用协议。另一方面,它又是一个与具体应用无关的通用协议,它仅仅提供了一些传输设施,所以它看起来也像一个传输协议。可能最恰当的描述是:它是一个在应用层上实现的传输协议。
RTP——实时传输协议
  • RTP的基本功能是将几个实时数据流复用到一个UDP数据包流中。这个UDP流可以被发送给一台主机(单播传输模式),也可以被发送给多台目标主机(组播传输模式)。因为RTP仅仅使用了常规的UDP,所以路由器不会对它的数据包由任何特殊的对待,除非开通了某些通常的IP服务质量特性。特别地,这里没有任何保障传递可靠性的措施,数据包可能会丢失、延迟或者损坏。
  • RTP格式包含了几种有助于接收端处理流媒体信息的特性。在RTP流中发送的每个数据包被赋予一个编号,而且每个数据包的编号比它前面的数据包编号大1.这种编号使得接收方能够确定是否有数据包丢失。如果一个数据包丢失,则接收方能够采取的最佳动作是交给应用程序来处理。如果数据包携带的是视频数据,或许可以跳过该视频帧;如果数据包携带的是音频数据,或许可以利用插值法近似地估算已丢失的值。重传不是一种切合实际的选择方式,因为重传的数据包可能到达得太晚以至于不再有用。因此RTP没有确认也没有请求重传的机制。
  • 每个RTP有效载荷可能包含多个样本,它们可以按照应用系统希望的任何一种方式进行编码。为了允许网络互连,RTP定义了几种配置轮廓(比如单音频流);而且对于每一种轮廓,又可以允许多种编码格式。例如,一个单音频流的编码方式包括使用增量编码以8kHz的8位PCM采样、预测编码、GSM编码、MP3编码等。RTP在头中提供了一个字段让源端用来指定编码方法;除此之外RTP不涉及如何进行编码。
  • 许多实时应用需要的另一种设施是时间戳机制。这里的想法是允许源端将每个数据包中时间戳与第一个样本关联起来。这里的时间戳是相对于整个流的起始时间,因此只有时间戳之间的差值才是最重要的,时间戳的绝对值没有任何意义。这种机制使得接收方可以做少量的缓冲工作,然后在整个流开始之后的正确毫秒时间点上播放每一个样本,并且独立于每个样本所在数据包的到达时间。
  • 时间戳机制不仅减小了网络延迟变化的影响,而且还允许在多个流之间实行同步。例如,一个数字电视节目可能有一个视频流和两个音频流。两个音频流中的内容可能是立体声广播,也可能是电影中的两个语言声道(一个原始语种的声音,另一个声音是本地语言的配音),从而让观众有选择语言的机会。每个流分别来自于不同的物理设备;但是如果它们的时间戳始于同一个计数器,那么即使这些流的传输和/或者接收过程稍微有一点不规律,它们仍然可以非常同步地播放出来。
  • RTP的头结构如图所示。它包含3个32位的字,并有潜在的一些扩展。第一个字包含了版本字段,现在版本号已经达到了2。我们希望这个版本非常接近于最终的版本,因为这里只剩下一个值了(虽然可以将3定义成说明版本号在一个扩展字中的特殊含义)。在这里插入图片描述
  • P位表示该数据包被填充到了4字节的倍数。最后的填充字节指明了有多少个字节被填充进来。X位表示有一个扩展头。扩展头的格式和含义没有定义。唯一定义的事情是扩展头的的第一个字给出了扩展头的长度。这是针对任何不可预见之需求的最后退路。CC字段指明了后面共有多少个贡献源,可从0到15。M位是一个与应用相关的标记位,可以用来标记一个视频帧的开始、音频信道中一个字的开始,或者其他由应用解释的某些事情。有效载荷类型说明使用了哪一种编码算法(比如未压缩的8位音频、MP3等)。由于每个数据包都带有这个字段,所以在传输过程中可以改变编码方法。序号只是一个计数器,每发送一个RTP数据包该计数器都要递增。该字段可被用来检测数据包的丢失。时间戳由媒体流的源端产生,它注明了数据包中的第一个样本什么时候产生的。这个值有助于减缓接收端的时间变化——称为抖动,具体做法是将播放与数据包的到达时间分离开。同步源标识符指明了该数据包属于哪一个流。正是通过这个字段,可以将多个数据流复用到一个UDP数据包流中,反之亦然。最后,如果在演播室中使用了混合器,则要使用贡献源标识符。在这种情况下,混合器是同步源,被混合的流就列在这里(即贡献源标识符)。
RTCP——实时传输控制协议
  • RTP中有一个姊妹协议,称为实时传输控制协议(RTCP)。它和RTP一起由RFC 3550描述。RTCP能处理反馈、同步和用户接口等信息,但不传输任何媒体样值。
  • RTCP的第一个功能是可以向源端提供有关延迟、抖动、带宽、拥塞和其他网络特性的反馈信息。编码进程重复利用了这些信息,当网络状况会好的时候,它降低数据速率。根据连续的反馈信息,编码算法可以不断地调整,从而在当前条件下尽可能提供最好的质量。例如,如果在传输过程中带宽增加或者减少,那么编码算法可以根据需要从MP3切换到8位的PCM,或者切换到增量编码。利用有效载荷类型字段可以告诉接收方当前数据包使用的是哪一种编码算法,因而有可能根据需要动态地改变编码算法。
  • 提供反馈信息的一个问题是要求所有参与者发送RTCP报告。对于一个规模较大的组播应用,RTCP协议使用的带宽会变得很大。为了防止这种情况发生,RTCP发送端缩减其报告率,使得总的带宽不超过媒体带宽的5%。要做到这一点,每个参与者需要媒体的带宽和参与者的数目。对于媒体带宽,它可以从发送端那里学习到这点;对于参与人数,它可以通过监听其他参与者的RTCP报告估算出来。RTCP也处理流之间的同步。问题在于不同的流有可能使用不同的时钟,并且有不同的粒度和不同的漂移速率,利用RTCP可使它们同步。最后RTCP还提供了一种命名不同源的方法(比如使用ASCII字符),这些信息可以显示在接收端的屏幕上,告诉用户此刻在跟谁通话。
带有缓冲和抖动控制的播放
  • 一旦媒体信息到达接收端,它必须在合适的时间播放出来。一般情况下,这个时间不是RTP包到达接收端的时间,因为数据包通过网络传输所需要的时间略有不同。即使在发送端,数据包以正确的时间间隔被依次注入网络,它们到达接收端的相对时间也不同。这种延迟的变化称为抖动。即使是少量的数据包抖动,如果简单地按它到达的时间播放出来,也可能导致媒体成品发散,如抖动的画面帧和难以辨认的音频。
  • 这个问题的解决方法是在接收端播放媒体之前对其进行缓冲,以此来减少抖动。如图,我们看到一个数据包流在传输过程中遭受了很大的抖动。在t=0时刻,服务器发出了数据包1,该数据包在t=1时刻到达客户端;随后的数据包2遭受了更多的延迟,它经过2秒才到达客户端。随着数据包的到达,它们均被缓冲在客户端机器上。在这里插入图片描述
  • 在t=10秒时,播放器开始播放媒体。这时,从数据包1到数据包6都已经在缓冲区中,因此它们以平滑播放的统一间隔从缓冲区移出。一般情况下,没有必要使用统一的间隔,因为RTP的时间戳告诉了播放器应该在何时播放相应的媒体。
  • 不幸的是,数据包8被延迟得太多,当播放它时还不可用。这种情况下有两种选择。第一种是跳过数据包8继续播放后续的数据包另一种方法是停止播放,直到数据包8到达,此时在播放的音乐或电影中就会出现一个恼人的间隙。在现场直播的媒体应用中,比如语音IP电话,延迟的数据包通常会被跳过去。直播应用在暂缓播放时无法很好地工作。在流媒体应用中,播放器或许可以暂停。通过延迟媒体的开始播放时间,可以缓解这个问题,但为此需要使用较大的缓冲区。对于流式音频或视频播放器,通常采用约10秒的缓冲区,以确保播放器按时接收所有数据包(即那些没有被网络丢弃的数据包)。对于像视频会议这样的实时应用,响应所需要的缓冲区较短。
  • 平滑播放的一个主要考虑因素是播放点设置在哪里,或接收器在播放媒体之前要等待多久。决定等待多长时间要取决于抖动。低抖动和高抖动连接之间的区别如图。两者之间的平均延迟没有很大的不同,但如果存在高抖动,则播放点可能要比低抖动多捕获超过99%的数据包。在这里插入图片描述
  • 为了寻找好的播放点,应用程序可以测量抖动,即考查RTP时间戳和数据包到达的时间之间的差异。每个差值给出了延迟的一个样本值(加上一个任意值,得到固定偏移)。然而,由于流量竞争和和路由变化等其他原因,延迟可能随时改变。为了适应这种变化,应用程序在运行时可以自适用播放点。但是如果做得不好,改变播放点可能会产生用户观察到的毛刺。对于音频来说,避免这个问题的一种方法是适应音频会话峰之间的播放点,即交谈中的间隙。没有人会注意到一个短的和稍长一点静默之间的差异。RTP协议允许应用程序为此目的设置M标志位,表明一个音频会话峰的开始。
  • 如果数据包的绝对延迟太长,以至于媒体播放时还没到来,那么直播应用将受到影响。如果已经使用了直接路径,那么无论做什么都无法减少传播延迟。可以简单地拖曳住播放点不动,然后接受太晚到达的大部分延迟数据包。如果这种处理方式不能接受,那么拽住播放点的唯一途径是通过使用一种更优质的服务来减少抖动,例如加速转发的区分服务,也就是说需要更好的网络。

猜你喜欢

转载自blog.csdn.net/ao__ao/article/details/88376944