高性能浏览器网络(High Performance Browser Networking) 第三章

第3章UDP篇

1980年8月,用户数据报协议(UDP)由John Postel添加到到核心网络协议族中,UDP协议起始于TCP/IP协议之后,但和TCP和IP规范被分裂成为两个独立的RFC的时间差不多。这个时机是非常重要的,因为正如我们将看到的,UDP重要的特点不是他带了什么新特性,而是他忽略了的那些特性。UDP(RFC 768)是通俗称为空协议,它描述的操作,基本上可以容纳在一张餐巾纸上。

数据报 一个自包含的,独立的数据实体,其承载了足够的信息,使其可以从源路由到达目标路由,而不依赖于在网络节点间和底层传输网络中的前面数据包。

数据报文(Datagram)和数据包(Packet)两个术语往交替使用,但其实二者有一些细微差别。数据包(packet)一般用来描述任何格式的数据块,而数据报(Datagram)往往被保留用来描述通过一个不可靠的服务传输的数据包(Packet) - 没有传输保障,没有失败通知。正因为如此,你经常发现有人用不可靠(Unreliable)来替代UDP官方定义中的User,我们可以理解成“不可靠的数据报协议”。这也是为什么UDP包一般或者说更准确的被称为数据报(Datagram)。

UDP的一个最著名的也是所有浏览器和网络应用都要依赖的应用就是DNS服务,任何一个Host名称,我们需要在数据交换之前获取它的IP地址。不过,即使是浏览器本身依赖于UDP的,但UDP从来没有作为网页获取和浏览器应用传输协议的第一选择。当然,WebRTC的出现,情况有所变化了。

新的Web实时通信(WebRTC)标准,由IETF和W3C工作组共同制定,实现实时通信,如语音和视频呼叫,以及其他形式的对等(P2P)通信,其就是在浏览器中采用了UDP。WebRTC中,UDP是首选的传输协议。我们将在第18章中深入讨论WebRTC ,但在此之前,我们首先探讨一下UDP协议的内部运作,了解一下WebRTC为什么选择UDP协议。

空协议服务

要了解UDP和为什么它通常被称为“空协议”,我们首先需要了解一下互联网协议(IP),它位于TCP和UDP协议层下面。

IP层主要任务就是基于地址将数据报从源主机发送到目的主机。要做到这一点,消息都封装在一个IP包( 图3-1 ),标识源和目的地址,以及一些其他路由参数。

我们再次强调一下上面提到的数据报这个术语的含义:IP层提供了不可靠的数据传输,既没有消息确认,也没有丢失通知, IP层直接把这一层的不可靠性暴露给上层。如果一个数据报在传输过程中因为某个路由节点拥塞,高负荷,或因其他原因丢失,那么由IP上层的协议来检测,恢复,并重传数据 - 当然这是在上层有这个需求的时候!

图3-1 IPv4报头(20字节)

UDP协议在IP包的基础上增加了新的报头( 图3-2 ),它只增加了四个额外的字段:源端口,目的端口,数据包长度,数据校验消息。因此,当IP层传送数据包到目的主机时,主机解开UDP数据包,通过目的端口识别目标应用程序,并发送消息。除此之外,再无其他。

图3-2 UDP报头(8字节)

事实上,UDP报头中的源端口和校验字段都是可选字段。IP数据包中已经包含它自己的报头校验和,应用层完全可以选择忽略UDP的校验字段,这意味着UDP层所有的错误检测和纠错,可以委托给上述应用层校验。其核心,UDP只是在IP层之上提供了“应用层复用”特性,也就是嵌入了源和目标端口。考虑到这一点,我们现在可以总结UDP所有不能提供的服务:

无消息传输保证

没有确认,重发,或超时

无法保证按序传输

没有数据包的序列号,没有重新排序,无线头阻塞

无连接状态跟踪

没有连接建立或关闭的状态机

没有拥塞控制

无内置的客户端或网络反馈机制

TCP是一个面向字节流的协议,能够通过多个数据包发送应用程序的消息数据,包内本身没有任何明确的消息边界。为了实现这一目标,连接两端都分配了连接状态,并且数据包被排序,重发丢包,按顺序发送。相反UDP数据报有明确的界限:每一个数据报都被打包到一个IP包中,应用层读到的每一个UDP包都是完整的信息 - 数据包不能被分割。

UDP是一个简单的,无状态的协议,适合于引导上层的其他应用层协议 - 几乎所有的协议决策都留给它上面的应用层。然而,在你想实现自己的协议来取代TCP,你应该仔细考虑有关的复杂性,如UDP与其它层的交互(比如NAT穿越),以及网络协议一些最佳实践。没有仔细的规划和设计,设计一个新的协议不是一个好主意,最终也许实现成一个的简陋的TCP版本。各种算法和TCP状态机已经过几十年的锤炼和提升,并已采取几十种机制来保证他的性能。

UDP和网络地址转换

非常不幸,IPv4地址只有32位长,它提供了最多42.9亿的IP地址。1994年中旬(RFC 1631),IP网络地址转换(NAT)规范,作为一个临时的解决方案,被提出来解决IPv4地址枯竭的问题 - 在上世纪90年代初期,互联网上的主机的数量开始成倍增长,我们根本无法为每台主机分配一个唯一的IP。

建议的IP重用的解决方案是在边缘网络中引入NAT设备,NAT将负责为维护本地IP和端口的元组到一个或多个全球唯一的(公共)IP地址和端口的元组的映射关系(图3 -3 )。NAT内部的本地IP地址空间可以被许多不同的子网络重用,从而解决地址耗尽的问题。

图3-3 IP网络地址转换

不幸的也是经常发生的是,临时方案最后总是变成最终方案。NAT设备不仅仅用来解决IP地址枯竭的问题,他们也很快成为一个无处不在的网络部件,包括许多企业和家庭代理和路由器,安全设备,防火墙,和几十个其他的硬件和软件设备都包含了NAT功能。NAT不再是临时方案了,它已经成为互联网基础设施的一个组成部分。

保留的私人网络地址范围

互联网编号分配机构(IANA),这是一个负责全球IP地址分配的机构,预留了三个著名的私人网络段,经常用在NAT设备内部网络:

表3-1. 保留的IP地址段


IP地址段


地址数量


10.0.0.0 - 10.255.255.255


16,777,216


172.16.0.0 - 172.31.255.255


1,048,576


192.168.0.0 - 192.168.255.255


65,536

大家应该熟悉上面所有或者部分地址段。基本情况是,本地路由器给您的计算机分配上面某个IP地址段中的一个地址 - 那是你在内部网络的私有IP地址,当与外部网络通信时,NAT将会做网络地址转换。

为了避免路由错误和混乱,公网主机不允许从上面任何这些保留的私有网络范围分配IP地址。

连接状态超时

NAT转换的关键问题,至少对UDP而言,是它必须保存数据传输的路由表。NAT依赖网络连接状态,而UDP恰好没有 - 这是一个严重的不匹配,这也为UDP传输问题的根源。此外,现在很普通的一个情况就是NAT内网的设备有很多层,这只会使问题进一步复杂化。

每个TCP连接有一个明确的协议状态机,开始三次握手,跟着开始数据传输,最后关闭连接,有一个完整的流程。基于这种流程,NAT可以观察到每个连接状态,并可以根据需要创建和删除的路由条目。而UDP,既没有握手,也没有连接终止,同时没有任何状态机来监控连接状态。

通过UDP往外发送数据并不需要任何额外的工作,但请求的答复却需要NAT维护路由表,用来识别本地目标主机的IP和端口。因此,NAT必须保持每个UDP流的路由表信息,因为UDP是无状态的。

更糟的是,NAT需要知道什么时候清除路由记录,但UDP没有连接终止序列,任何时候,两端都可以停止发送数据包,不带任何通知。为了解决这个问题,UDP路由记录有一个老化定时器。这个定时器到底多长?”基本上没有明确的答案,而是取决于设备提供商,版本,配置等。因此,事实上长时间运行的UDP会话的最佳实践之一就是引入双向 keepalive报文,定期的重置路由上所有的NAT设备的老化计时器。

TCP超时和NAT

从技术原理上来说,在NAT设备没有必要为TCP连接提供超时老化机制。TCP协议有一个良好握手机制和终止序列包,NAT可以清晰的根据这些信息来添加或者删除路由记录。

不幸的是,在实际应用中,许多NAT设备为TCP提供了类似UDP的老化计时器。其结果是,在某些情况下,TCP连接也需要双向Keepalive报文。如果你的TCP连接突然下降,也许就是NAT设备的老化机制惹的祸。

NAT穿越

不可预知的连接状态管理是NAT的一个严重问题,但对于许多应用程序的一个更大的问题是根本无法建立UDP连接。这对很多应用譬如P2P,如VoIP,游戏,文件共享等来说更是如此。这些应用往往通信双方需要同时充当客户端和服务端角色,使其能双向通信。

第一个问题是,在有NAT的场景下,内部客户端不知道它的公网IP??:它只知道它的内部IP地址,NAT设备对每一个UDP数据包进行重写,修改UDP包的源端口和地址,以及IP层的源IP地址。但是,如果客户端将私有IP地址作为应用层数据的一部分与外部网络地址进行通信,那么连接将不可避免地失败。因此,NAT这种“透明”的转换就有问题了,应用程序必须先发现它的公网IP??地址,如果它需要与外部网络中的一个地址进行通信。

然而,仅仅知道的自己的公网IP是无法保证UDP传输成功的。任何数据包到达拥有公网IP的NAT设备后??,也??有一个目的端口,NAT路由表中必须有一个外网IP端口与内网地址和端口的映射记录,数据才能真正达到目的地址。如果这个记录不存在,那么数据包被简单地丢弃(图3-4 )。NAT作为一个简单的包过滤器,它没有办法自动确定内部路由映射关系,除非用户通过端口转发或者类似机制显式在NAT上进行了登记。

图3-4 由于缺少映射记录,收到的包被丢弃

需要注意的是,上面描述的问题对于客户端应用程序来说不是一个问题,客户端从内部网络中先发起连接,NAT自然会添加相应的路由。但是,对于那种需要主动接收连接(内网主机作为服务器)的应用如P2P应用(如VoIP),游戏终端,文件共享等等,就会碰到这个问题。

为了解决这种UDP的穿越问题,各种穿越技术(STUN,TURN,ICE)被提出了,用于建立在 两个内网主机之间建立端至端的连接。

STUN,TURN,ICE

STUN(RFC 5389)协议是一种允许主机应用程序发现网络中的NAT设备,并借助其来为当前连接分配公网IP??和端口元组(图3-5 )的方案。要做到这一点,该协议需要借助一个第三方部署在公网上的STUN服务器。

图3-5 STUN查询公网IP和端口

假设STUN服务器的IP地址是可知的(通过DNS发现,或通过手动指定的地址),应用程序首先发送绑定请求到STUN服务器。相应的,STUN服务器回复一个响应,其中包含为其分配的客户端对外暴露的公网IP??地址和端口。这个简单的流程解决我们了我们前面讨论中遇到的几个问题:

  • 该程序通过该方式获取了其公网IP和端口的元组,并使用这个信息,作为其应用数据的一部分,就能够与对端进行通信。
  • 向STUN服务器发送的请求,也同时在NAT上建立了路由映射记录,这确保了对端的请求可以准备达到内部网络中的应用。
  • STUN协议定义了一个简单的机制来保持NAT上的路由老化。

有了这个机制,两端需要通过UDP进行通信时,他们会先发送绑定请求到各自的STUN服务器,收到各自STUN服务器的响应,然后他们可以使用各自分配的公共IP地址和端口进行数据交换了。

然而,在实际应用中,STUN是不足以处理所有的NAT的拓扑结构和网络配置。此外,不幸的是,在某些情况下,UDP可能会被防火墙或其他一些网络设备完全阻止 - 这种许多企业网络中不是一种罕见的情景。为了解决这个问题,只要STUN失败,我们还可以使用TURN协议(RFC 5766)作为备用方案,它可以运行在UDP上,还可以将UDP转换成TCP。

TRUN方案的关键就是中继(relay)。该协议依赖于公网上的中继来保证私网主机的可见性和可用性( 图3-6 )。

图3-6 TURN中继服务器

  • 两端都向相同的TURN服务器发送地址分配请求,其次是权限协商。
  • 一旦协商完成后,两端通过将数据发送到TURN服务器,并由TURN进行转发到对端的方式进行互相通信。

当然,这种通信方式的最明显的缺点就是他不再是P2P的通信。他需要依赖于TURN服务器来保证可靠的传输,TURN服务器成为一个瓶颈,维护TURN的成本将很高,至少TURN服务器需要足够的带宽来保证所有的数据流。因此,TURN方案最好作为最后的备用方案,只有在其他方案都失效的情况下才能使用。

STUN和TURN实践

google提供的Libjingle,是一个开放源码的C + +库,可以用它来创建P2P的应用,它在底层实现了STUN,TURN,ICE等协商。这个库用在Google Talk中,库文档为STUN与 TURN在现实世界中的性能提供了有价值的参考点:

  • 92%的时间可以直接连接方案(STUN)
  • 8%的时间连接需要一个中转器(TURN)

不幸的是,即使采用STUN方案,有部分用户还是无法建立直接的P2P隧道。为了提供可靠的服务,我们还需要TURN中继,它可以作为STUN方案不可用情况下的一个备选方案。

建立一个有效的NAT穿越解决方案,不是一件简单容易的事情。值得庆幸的是,我们可以借助ICE协议(RFC 5245)来帮助我们完成这一任务。ICE是一个协议,和一组方法,用来寻求最有效的端与端之间(图3-7 )隧道建立方法:如果可能则直接连接,如果不行则通过STUN进行协商,如果都失败了则采取TURN。

图3-7 ICE试图通过直接连接,STUN和TURN建立连接

在实践中,如果你正在建设一个基于UDP的P2P应用程序,那么你最希望利用现有的平台API或第三方的库,为您实现ICE,STUN和TURN。现在你应该了解了这些协议,现在你可以跳转到相应的安装和配置去实现你的方案了!

UDP优化

UDP是一种简单而常用的协议。事实上,UDP的主要特征是它忽略了的功能:无连接状态,握手,重发,重组,重新排序,拥塞控制,拥塞避免,流量控制,甚至可选的错误检查。然而,这个面向消息的传输层能提供的灵活性,也是实现者的责任。您的应用程序可能从头开始重新实现部分或者许多缺失的特性,每一个特性都应该需对端或者应用协议匹配。

与TCP不同,内置了流量和拥塞控制、拥塞避免机制,UDP应用程序必须自己实现这些机制。拥塞不敏感的UDP应用程序可以很容易的拥塞网络,可能会导致网络性能降低,在严重的情况下,会导致网络拥塞崩溃。

如果你想在自己的应用程序中使用UDP,确保研究和阅读当前的最佳实践和建议。在RFC 5405中,特别强调了应用程序通过单播UDP传送数据设计指南。下面是一个简短的例子:

  • 应用必须忍受变化的互联网路径
  • 应用应控制传输速率
  • 应用应当实现所有流量拥塞控制
  • 应用应该使用和TCP同等的带宽
  • 应用当丢包时应该回退重传计数器
  • 应用不应该发送超过MTU的数据报
  • 应用应该处理数据报的丢失,重复,重新排序
  • 应用应该是确保可以支持两分钟的延迟
  • 应用应该启用IPv4 UDP校验,必须启用IPv6校验
  • 应用可能在需要的时候使用保活(最小间隔15秒)

设计一个新的传输协议,需要很多的认真思考,规划和研究 - 做你的尽职调查。在可能的情况下,充分利用现有的库或已经采用了一个现有框架来实现NAT穿越,使其能够与其他来源的网络建立某种程度的公平通信。

关于这一点,好消息, WebRTC就是这样一个框架!

时间: 2024-10-22 18:02:04

高性能浏览器网络(High Performance Browser Networking) 第三章的相关文章

高性能浏览器网络(High Performance Browser Networking) 第一章

译者注:本文是<High Performance Browser Networking>的翻译版,采用google translator tookit工具翻译,原文很多格式丢失,后续还需要统一整理. 原文请参考:http://chimera.labs.oreilly.com/books/1230000000545/ch01.html 第一章 延迟和带宽的基本概念 速度是一个特性 过去几年内,Web性能优化(WPO)作为一个新的行业快速增长,成为用户追求更高的速度和更快的用户体验的一个明显标志.

高性能浏览器网络(High Performance Browser Networking) 第二章

第2章 TCP篇 互联网的核心是两个协议,IP和TCP. IP也叫Internet协议,提供主机到主机的路由和寻址:TCP,传输控制协议,在不可靠的传输通道上提供一个可靠的网络抽象.TCP / IP协议也通常被称为Internet协议套件,在1974年,它首次在一篇题为<一个用于分组网络互通的协议>的论文中被Vint Cerf和Bob Khan提出. 最初的RFC建议(RFC 675)几经修订,在1981年发表TCP / IP V4正式规范,但分为了两个独立的RFC: RFC 791 - In

High Performance Browser Networking

Table of Contents Foreword Preface About This Book Conventions Used in This Book Safari? Books Online How to Contact Us Content Updates May 23, 2014 I. Networking 101 1. Primer on Latency and Bandwidth Speed Is a Feature The Many Components of Latenc

高性能浏览器网络(High Performance Browser Networking) 第五章

Ubiquitous Connectivity One of the most transformative technology trends of the past decade is the availability and growing expectation of ubiquitous connectivity. Whether it is for checking email, carrying a voice conversation, web browsing, or myri

High Performance Browser Networking - TCP UDP TLS

时延 时延的定义和标准 时延简单的说是从原点到目标点传送一条信息或者一个数据包,所花费的时间. 时延=发送时延+传播时延+处理时延+排队时延: Propagation delay 传播时延 传播时延这个概念,是指电磁信号或者光信号在传输介质中传输的时延,而在光纤或者铜线中,光信号和电磁信号的传播速度都在20万公里/秒以上,在传输介质中传输的是电磁信号或者光信号,而不是数据! Transmission delay 传送时延 发送时延是指结点在发送数据时使数据块从结点进入到传输媒体所需的时间,也就是

Voovan 是一个高性能异步网络框架和 HTTP(Java)

Voovan 是一个高性能异步网络框架和 HTTP 服务器框架,同时支持 HTTP 客户端抓取.动态编译支持.数据库访问封装以及 DateTime.String.Log.反射.对象工具.流操作.文件操作.异步双向通道等功能.旨在提供可靠.方便.可单元测试的代码.它是一个无任何依赖的独立工具包,希望能够方便广大开发者快速的实现应用. 作者:@愚民日记 地址:http://git.oschina.net/helyho/Voovan http://www.oschina.net/news/80909/

Netmap to VALE—— 从高性能网络框架到高性能虚拟网络交换机

我在上一篇文章也提到过,对于全虚拟化和半虚拟化,需要分配给虚拟机一个虚拟网络接口,这些就需要一个虚拟交换机vswitch(可以和hypervisor一同使用),从而将虚拟网络接口的数据包从物理接口转发出去.但是在复杂的系统中,这个虚拟交换机的性能往往并不好.开源项目netmap[1]做了一个高性能网络框架,并且同样使用这个原理完成了高性能虚拟网络交换机vale的设计[2],在多种场景下Vale测量的性能[3]也非常好.  note:由于项目需要,我常常思考一个高性能的虚拟交换机应该怎么做.从ne

浏览器性能接口performance.timing说明

原文来自于 https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html 下图描述了该接口的各个时间点: performance.timing API 各个时间点含义如下: navigationStart 当访问一个新页面时,当前页面卸载完成所返回的时间点,如果没有当前页面,则返回fetchStart时间点. unloadEventEnd 如果要打开的页面和当前的页面同源,则返回用户unload事

【服务器】构建高性能Linux网络服务器

关键 高性能网络服务器的关键在于并发,如何高效的使用多核心的服务器,让多个线程并发处理程序. 并发方式 基于时间的并行 基于空间的并行, 其他提法, 在计算机内部,最本质的是时间(CPU)和空间(内存)这两种资源,各种并行的界限并没有那么明显.所谓基于时间的并行,有两只猫,共同看守一个大仓库,但一个工作,另一个睡觉,两者不同时工作.所谓基于空间的并行,将仓库分为两个部分,这样两只猫可以分别看守不同的部分,两只猫在工作不紧张的时候就可以睡觉. 网络并发程序优化 对于网络并发程序,可以从各个角度进行