网络协议五步登天路,我们一路迈过了物理层、链路层,今天终于到了传输层。从这一层开始,很多知识应该都是服务端开发必备的知识了,今天我们就一起来梳理下。
其实,讲到 UDP,就少不了 TCP。这俩货简直就是个“连体兄弟”,只要出现一个,另一个肯定就在不远处等着你。
博主相信,绝大多数的服务端开发都碰到过“TCP 与 UDP 的区别”这样的面试题,而在实际业务开发中,也会对比 TCP 与 UDP,选择合适的协议进行开发。
所以,咱们还是老生常谈,先来看看这俩兄弟的区别。
TCP 与 UDP 的区别
相信很多人都知道,TCP 是面向连接的,UDP 是面向无连接的。
那么,什么是面向连接,什么是面向无连接呢?
在互通之前,面向连接的协议会先建立连接,再进行通信。就像 TCP 会进行三次握手,而 UDP 不会。
那为什么会建立连接呢?TCP 进行三次握手,UDP 就不能发三个数据包玩玩,有什么区别呢?
其实这里所谓的建立连接,就是通过建立一定的数据结构来维护客户端和服务端交互的状态,用这样的数据结构来保证所谓的面向连接的特性。
上面这段话中,有一个很重要的词-状态。也就是说,TCP 实质上是一个有状态的服务。这个状态,可以说是它和 UDP 的本质区别。
通俗点讲,有状态的 TCP 就是有脑子的,它会记住数据是否已经精确发送了,发到哪里了,应该接收哪个数据,不能容忍一点错误。
与之对应的,UDP 就是没脑子的,天真无邪,发出去的数据就发出去,不会考虑网络世界的“恶意”。
TCP 既然有脑子,那肯定能做到很多 UDP 做不到的事情,例如:
- 提供可靠交付。通过 TCP 连接传输的数据,无差错、不丢失、不重复,且按序到达。而 UDP 则是不保证不丢失,不保证按序到达。
- 面向字节流。TCP 发送的时候是一个流,没有头尾。而 UDP 是基于数据报,一个个发,一个个收;
- 可进行拥塞控制。TCP 意识到包丢弃或者网络环境不好的时候,会调整自己的行为,决定要发快点,还是发慢点。而 UDP 则是应用让我发,我就发,管它洪水滔天。。
UDP 包头
发送的 UDP 包到达目标机器后,发现 MAC 地址匹配,于是取下来,然后再交给 IP 层处理,发现 IP 匹配,接下来呢?数据包给谁呢?
发送的时候,接收机器怎么知道数据包是 UDP 的包呢?所以在 IP 头里面有个 8 位协议,这里会存放,数据包究竟是 TCP 还是 UDP。
处理完传输层的事情,内核的事情基本上就干完了,里面的数据应该交给应用程序自己去处理。可是,一台机器上跑着那么多的应用程序,应该给谁呢?
无论应用程序写的是使用 TCP 传呼机,还是 UDP 传数据,都要监听一个端口。正式这个端口,用来区分应用程序。
这样,UDP 头里面的内容就都出来了,如下图:
当我们看到 UDP 包头的时候,发现的确有端口号,有源端口号和目标端口号。但是它除了端口号,就再没有其他的,和 TCP 头比起来,简单的一塌糊涂。
UDP 三大特点
上面提过,UDP 像个小孩子一样,比较简单,有以下特点:
- 沟通简单。没有花花肠子(大量的数据结构、处理逻辑、包头字段),秉承“性善论”,相信网络通路很容易到达,不容易被丢弃;
- 轻信他人。不会建立连接,只认端口号,谁都可以给他传数据,他也可以传给任何人数据,甚至可以同时传给多人数据;
- 愣头青,做事不懂权变。不会根据网络的请求进行拥塞控制,不管网络再差,它该怎么发还怎么发。
UDP 使用场景
正所谓“祸兮福所倚”,虽然 UDP 有着很多问题,但也可以在特定场景中发挥更好的作用。
第一,需要资源少,在网络情况比较好的内网,或者对于丢包不敏感的应用。这很好理解,就像你是领导,你会让你们组刚毕业的小伙伴去做一些没有那么难,或者是失败了也能忍受的实验性项目。
我们之前认识的 DHCP 就是基于 UDP 协议的。一般的获取 IP 地址都是内网请求,而且一次获取不到 IP 也没关系,过一会还可以请求获取。
第二,不需要建立连接,一对一沟通,而且需要广播的应用。 UDP 的不面向连接的功能,可以承载广播或多播的协议。DHCP 就是一种广播的形式。
对于多播,我们之前提到的 IP 地址中的 D 类地址,也就是组播地址。使用这个地址,可以将包组播给一批机器。当一台机器上的某个进程想监听某个组播地址时,需要发送 IGMP 包,所在网络的路由器收到这个包,知道有个机器有个进程在监听这个组播地址。当路由器收到这个组播地址的数据包时,就会将包转发给这台机器,这样就实现了跨路由器的组播。
第三,需要处理速度快、延时低、可以容忍少数丢包,但是要求即便网络阻塞,也毫不退缩,一往无前的时候。
UDP 简单、处理速度快,不像 TCP 那样操那么多的心。并且,TCP 在网络不好出现丢包的时候,它的拥塞策略会主动的降低发送速度,这就相当于本来环境就差,还自断臂膀,用户本来就卡,这下更卡了。
当前很多应用都是要求低时延的,他们可不想用 TCP 如此复杂的机制,而是想根据自己的场景,实现自己的可靠和连接保证。例如,如果应用觉得,有的包丢了就丢了,没必要重传了,而有的比较重要的包丢了,则应用自己重传,不依赖 TCP。
由于 UDP 十分简单,基本啥都没做,也就给了应用“城会玩”的机会。就像在和平年代,每个人应该有独立的思考和行为,应该可靠且礼让。但是如果在战争年代,往往不太需要过于独立的思考,而需要士兵简单服从命令即可。
基于 UDP 的“城会玩”的五个例子
城会玩 一:网页或 APP 的访问
网页和手机 APP 都是基于 HTTP 协议的,而HTTP 协议是基于 TCP 的,建立连接都需要多次交互,对于时延比较大的移动互联网来讲,建立一次连接需要的时间会比较长,而且移动互联网还是在移动中,TCP 可能还会断了重连,这也是很耗时的。
除此之外,目前的 HTTP 协议,往往采取多个数据通道共享一个连接的情况这样本来为了加快传输速度,但是 TCP 的严格顺序策略使得哪怕共享通道,前一个不来,后一个和前一个即便没关系,也要等着,时延也会加大。
而 QUIC(Quik UDP Internet Connections,快速 UDP 互联网连接)是 Google 提出的一种基于 UDP 改进的通信协议,其目的是降低网络通信的延迟,提供更好的用户互动体验。
QUIC 在应用层会自己实现快速连接建立、减少重传时延,自适应拥塞控制,是应用层“城会玩”的代表。
“城会玩” 二:流媒体的协议
直播协议多使用 RTMP,这个协议就是基于 UDP 的。TCP 的严格顺序传输要保证前一个收到了,下一个才能确认。对于直播来讲,这显然是不合适的,因为老的视频帧丢了就丢了,就算再传过来用户也不在意,他们要看新的了,如果一直没来,用户就会一直显示卡顿,新的也看不了。所以,对于直播,实时性比较重要,宁可丢包,也不要卡顿的。
另外,对于丢包,其实对于食品播放来讲,有的包可以丢,有的包不能丢,因为视频的连续帧里面,有的包重要,有的包不重要,如果必须要丢包,隔几个帧丢一个,其实看视频的人不会感知,但是如果连续丢帧,用户就会有感知了。因此,在网络不好的情况下,应用希望选择性的丢帧。
还有就是,当网络不好的时候,TCP 会主动降低发送速度。这对本来就卡的看视频来讲是要命的,本来应该马上重传,而不是主动让步。因此,很多直播应用,都基于 UDP 实现了自己的视频传输协议。
“城会玩” 三:实时游戏
游戏有一个特点,就是实时性比较高。快一秒你干掉别人,慢一秒就被别人爆头,所以很多职业玩家会买非常专业的鼠标和键盘,争分夺秒。
因而,实时游戏中客户端和服务端要建立长连接,来保证实时传输,但是游戏玩家很多,服务器却不多,由于维护 TCP 连接需要在内核维护一些数据结构,因而一台机器能够支撑的 TCP 连接数量是有限的。而 UDP 由于是没有连接的,在异步 IO 机制引入之前,常常是应对海量客户端连接的策略。
另外还是 TCP 的强顺序问题,对战的游戏,对网络的要求很简单,玩家通过客户端发送给服务器鼠标和键盘行走的位置,服务器会处理每个用户发送过来的所有厂家,处理完再返回给客户端,客户端解析响应,渲染最新的场景展示给玩家。
如果出现一个数据包丢失,所有事情都需要停下来等待这个数据包重发。客户端会出现等待接收数据,然而玩家并不关心过期的数据,相信大家玩CF 的时候,如果激战中卡 1 秒,是不是就有拍键盘的冲动?
游戏对实时要求较为严格的情况下,采用自定义的 UDP 协议,自定义重传策略,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性能造成的影响。
“城会玩” 四:IoT物联网
一方面,物联网领域终端资源少,很可能只是内存非常小的嵌入式系统,而维护 TCP 协议代价太大。另一方面,物联网对实时性要求也很高。Google 旗下的 Nest 建立 Thread Group,推出了物联网通信协议 Thread,就是基于 UDP 协议的。
“城会玩” 五:移动通信领域
在 4G 网络里,移动流量上网的数据协议 GTP-U 也是基于 UDP 的。因为移动网络协议比较复杂,而 GTP 协议本身就包含复杂的手机上线下线的通信协议。
总结
-
如果把 TCP 比作成熟的社会人,那么 UDP 就是头脑简单的小朋友。TCP 复杂,UDP 简单;TCP 维护连接,UDP 谁都相信;TCP 会知进退,UDP 愣头青一个,勇往直前;
-
UDP 虽然简单,但是它可以用在环境简单、需要多播、应用层自己控制传输的地方。例如 DHCP、QUIC 等。
参考:
- 百度百科-UDP 词条;
- 刘超-趣谈网络协议系列课;