1. UDP是最纯洁的传输层协议
实际上,UDP并不是像大家想象中的那样不可信,它只是因为简单,才让你有这样的认知。从另一个角度来说,它其实是最纯洁的传输层协议。
那么UDP在网络传输中,到底处于一个什么位置呢?我们需要简单看一下典型的网络分层。
SRC
和DST
(这里是mac地址),得以让我们的两台机器进行点对点通信这时候网络数据包还不能逃离局域网,想要更大规模的传输,就需要网络层的帮助。
为了让这些地址有意义, 网络层
加入了IP协议
,通过IP地址进行目标机器的定位,最后经过路由器的转换,由连接层负责具体信息的传输。比如我在下面的这个wireshark的抓包。
EthernetII
就是我们所说的连接层以太网,传输的信息是Frame如果你去看一下IP的报文,会发现它的格式是非常怪异的,中间节点在路由的时候,需要走先解包然后再封包的过程。这是由于IP协议是网络层协议,它的头信息,比如IP地址,其实是连接层协议的报文体(playload)。
到了IP协议,我们已经离UDP很近了。
IP协议只是解决了计算机到计算机之间的通信问题,但我们每台机器上还会有不同的进程,如何区分它们呢?这就是传输层
协议要干的事。
UDP和TCP协议,通过加入了端口号,来识别某一个进程。IP地址加上端口号,就是我们写代码需要面对的socket。现在的大多数网络通信,包括HTTP/1,HTTP/2等,都是基于TCP。
从协议层面来看,UDP其实是最干净的协议,它完完全全的暴露了IP协议的所有内容。相比较IP协议,它仅仅多了一个端口号,所以UDP协议拥有IP协议的所有特点。比如无序性,不保证可靠性(Best Effort)。至于拥塞机制这种更高级的流量协商控制,UDP根本就不管这些。
UDP这种没有特性的特性,使得应用面比TCP窄的多。我们通常把**TCP/IP**
协议作为一个整体去介绍,以至于忽略了最原始最纯洁的UDP协议。
我们来看一下一个典型的UDP协议。如上图,相对于IP协议,UDP协议仅仅多了两个端口,一个长度,一个checksum,确实是无与伦比的纯洁。
你可能会问,TCP和UDP都是传输层协议,那为什么HTTP/3不是基于TCP呢?那是因为TCP本身就已经非常复杂了,有太多历史遗留的包袱。
为了保证信息的可靠传输,顺序传输,同时兼顾吞吐量,TCP做了大量工作。相比较UDP,我们可以看一下TCP的协议都多了哪些内容。如图,是一个wireshark抓取的,典型的TCP协议包。
我们常说的三次握手(四次合并成三次),四次挥手,就是Flags和序列号逻辑组合的结合体。如果加入了TLS安全协议,这个握手的过程会更长。
连接建立后,由于采用了一问一答的ACK确认模式,TCP的效率其实是不怎么高的。它要传输很多无用信息,还得等待。
为了提高网络传输效率,TCP使用滑动窗口来解决批量发送,同时解决顺序性问题。为了解决网络拥塞,TCP使用慢启动、拥塞避免、快速重传、快速恢复等机制,使得网络吞吐量保持在一定的水平。
我们可以看一下wikipedia上TCP协议的一张细节图,在《TCP/IP详解 卷一:协议》中,对此进行了非常详细的介绍。可以看到细节问题还是非常多的。
那什么叫做协议?协议,就是规定了大家都遵守的标准,所有协议都是利益共同体共同商定的结果。比如我的分布式数据库使用了MySQL的接入层协议,那么就要遵循MySQL协议所制定的一系列标准,否则就跑不起来。
**协议越底层,对稳定性要求就越高。**TCP协议,目前已经被编码到了操作系统,不论是协议升级,还是BUG修复,都是伤筋动骨的。
为了抛开历史的包袱,HTTP/3
选择了UDP
,主要是为了解决对头阻塞问题。它的底层协议,就是大名鼎鼎的QUIC
,一个运行在传输层(也可以说是应用层)的协议。与TCP
不同的是,QUIC代码并没有硬编码在操作系统内核中,而是完全运行在用户空间的,默认集成了TLS。
如上图所示,HTTP/3基于QUIC,而QUIC是完全基于UDP的。
但UDP不是号称无连接的么?它怎么去实现可靠性等一些额外的功能呢?
其实,连接
这个词,是一个虚拟的概念,在网络中根本就没有连接这么一条线,连接
只是为了方便你逻辑上的理解。考虑到你现在的客户端服务器是client,服务端是server。那么client和server的数据包交互,就可能会有下面这种行走路径。
在没有数据交互的时候,server和client就是单纯的两个点。即使你拔了网线重新插上(期间无交互),它们依然可以继续相互间发送数据。
UDP号称的无连接,其实和TCP的连接没什么两样。唯一的区别是,UDP把数据包发送之后,就什么也不管了,这些信息对端可能收到了,也可能没收到。而当每次都对发送的数据进行ACK确认,它就变成了TCP。
至于这部分确认代码,是放在传输层,还是放在应用层,这都关系不大;但代码是放在操作系统,还是可以独立升级的包中,那关系可就大了。
QUIC是可以独立于操作系统发行的,避免了操作系统缓慢的更新换代问题。QUIC的实现,依然要面对消息的可靠性、滑动窗口、拥塞控制等场景,你可以认为它就是一个TCP,但它与TCP有本质的区别。
这些区别,我们对比一下HTTP的各个版本,在数据传输方面的表现就知道了了。
队头阻塞现象(Head-of-line blocking)
了解了以上内容,相信你一定能得出结论:HTTP/3基于UDP,是非常靠谱的。它不仅实现了可靠性传输,而且能够获得较大的性能提升。我们来总结一下QUIC的这些改进:
QUIC产生的原因,主要是由于TCP的限制所引起的。连接是一种非常宝贵的资源,创建、销毁,以及其上的传输,都是非常耗时的。TCP的可靠性机制,在计算机网络发展的早期,确实是非常有效的,但随着硬件的升级,它的ACK传输模式,在效率上制约了更高性能的发展。由于TCP标准的概念深入人心,它的代码甚至直接存在于内核上,使得协议升级困难。
随着网络基础设施的提升,TCP的这种可靠传输模式,反而成了制约。如果我们的信息处理,能够全部在一条连接上完成,那就太好了。这样,在一些密集的资源传输时,比如批量小图片、视频点播、弱网传输时,就不会受到RTT的影响。另外我的数据缓存和拥塞控制等,也会更加灵活。举个极端的例子,我的内存足够大能把stream缓存起来,我甚至能够忍受某个1MB大小的文件,10秒钟后文件的第一个字节到达,而不是像TCP一样一直重传重传(因为它受限于TCP窗口)。
为什么能够这么做呢?还是得益于UDP纯洁的属性,它只是IP协议的一个编程接口,它真的是一张白纸,什么都没有。如果你愿意,你甚至可以在UDP的基础上,完全复刻TCP的所有功能,只要你能把server端和client端对应起来。这就是QUIC所做的。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。