目录
- 导语
- [3.3 无连接运输:UDP](#3.3 无连接运输:UDP)
- [3.3.1 UDP报文段结构](#3.3.1 UDP报文段结构)
- [3.3.2 UDP检验和](#3.3.2 UDP检验和)
- 本节核心总结
- 结语
导语
在上一节(3.2)中,我们学习了多路复用 (Multiplexing)和多路分解(Demultiplexing)的概念,知道了运输层如何把网络层的主机到主机交付服务,扩展为运行在主机上的应用程序之间的端到端交付服务。我们还了解了端口号的作用------它是运输层将数据交给正确应用程序的"门牌号"。
那么,运输层到底提供了哪些具体的协议来实现这种端到端交付呢?从这一节开始,我们就来认识第一个运输层协议------UDP(User Datagram Protocol,用户数据报协议)。它简单、轻量、快速,就像一辆没有安全装备的摩托车,虽然不够"安全",但胜在"快"。
3.3 无连接运输:UDP

UDP (User Datagram Protocol,用户数据报协议)是因特网运输层两个主要协议中最简单的一个。如果说TCP(Transmission Control Protocol,传输控制协议)是一辆全副武装的装甲运输车,那UDP就是一辆轻便的摩托车------没有握手仪式,没有安全检查,上去就骑,到了就扔。
UDP的核心特征
UDP在做数据传输这件事上,可以说是一个"极简主义者"。它只做最基本的事情------把数据从发送方送到接收方,其他一概不管。具体来说,UDP具有以下特征:
- 无连接(Connectionless):UDP在发送数据之前不需要先建立连接。没有所谓的"握手"(handshake)过程,发送方想发就发,接收方收了就收。这就像寄明信片------你不需要先跟收信人打电话确认他在不在家,写好地址直接丢进邮筒就行。
- 不可靠(Unreliable):UDP不保证数据能到达目的地,也不保证按顺序到达。数据可能在路上丢失、乱序,UDP不会重传,也不会告诉你"嘿,刚才那个包丢了"。
- 无流量控制(No Flow Control):UDP不管接收方能不能处理得过来,发送方只管按照自己的节奏发。如果接收方来不及处理,数据就被丢弃,没有反馈机制。
- 无拥塞控制(No Congestion Control):UDP不关心网络是否拥堵。即使网络已经堵成一锅粥,UDP照样全速发送,不会主动减速。
- 首部开销小 (Small Header Overhead):UDP的首部只有8个字节,相比TCP动辄20字节以上的首部,UDP的"行李"轻得多。
为什么需要UDP?
看到上面这些特征,你可能会问:既然UDP这么"不靠谱",为什么还要用它?答案很简单------因为快,因为简单。
想象一下你在打网络游戏或者看实时直播。在这种场景下,速度比可靠性重要得多。如果某个数据包丢了,你宁可丢掉这一帧画面继续看,也不愿意停下来等重传,因为那会造成卡顿和延迟。UDP正好满足了这个需求:不管那么多,先送过去再说。

UDP的典型应用场景包括:
- DNS(Domain Name System,域名系统):DNS查询通常只有一个请求和一个响应,建立TCP连接的开销太大,用UDP快多了。
- SNMP(Simple Network Management Protocol,简单网络管理协议):网络管理中需要频繁采集数据,UDP的低开销非常适合。
- 实时多媒体应用(Real-time Multimedia):视频会议、直播流媒体等,对实时性要求高,偶尔丢几帧无所谓。
- 在线游戏(Online Gaming):游戏中的位置更新、动作同步等数据,需要低延迟传输,丢了就丢了,下一帧更新就行。
UDP vs TCP:首部对比

UDP和TCP最大的区别之一就是首部大小。UDP的首部只有8个字节,4个字段,简单明了。而TCP的首部至少20个字节,包含了序号、确认号、窗口大小等一大堆字段。这意味着在传输同样多的应用数据时,UDP的"额外开销"更小,传输效率更高。
3.3.1 UDP报文段结构

UDP报文段(segment)的结构非常简单,可以分为两部分:首部 (Header)和数据(Data)。
首部一共8个字节 ,由4个字段 组成,每个字段都是2个字节(16位):
- 源端口号(Source Port Number):发送方的应用程序端口号。这个字段是可选的------如果不需要接收方回信,可以填全0。
- 目的端口号(Destination Port Number):接收方的应用程序端口号。这个字段是必须的,不然接收方的运输层不知道该把数据交给谁。
- 长度(Length):整个UDP报文段的长度,包括首部和数据,以字节为单位。最小值是8(只有首部没有数据的情况)。
- 检验和(Checksum):用于检测报文段在传输过程中是否出错。这个字段是UDP唯一提供"保护"的地方。
首部之后就是数据字段(Data field),里面装的是应用程序要发送的数据。这个字段的大小是可变的,取决于应用层交给UDP多少数据。
理解UDP报文段结构的关键在于它的"极简":4个字段,8个字节,没有序号,没有确认号,没有窗口大小,没有任何控制信息。UDP就是在告诉你:"我只负责把数据送到,其他的你自己看着办。"
3.3.2 UDP检验和

虽然UDP是一个"极简主义"协议,但它并非完全不关心数据的正确性。UDP提供了检验和(Checksum)机制,用于检测报文段在传输过程中是否发生了比特错误。
检验和的计算方法
UDP检验和的计算过程可以概括为以下几步:
- 在发送方,将UDP报文段的内容(包括首部和数据)看作一系列16位的字(word)。如果数据长度不是16位的整数倍,则在末尾填充0(padding),但填充的字节不实际发送。
- 将所有这些16位字进行二进制反码求和 (one's complement sum)。如果求和过程中产生了进位(carry),则将进位回卷(wrap around)加到结果的最低位。
- 对求和结果取反码 (one's complement),得到的值就是检验和。
- 将检验和填入UDP首部的检验和字段。
在接收方,对收到的整个UDP报文段(包括检验和字段本身)执行同样的反码求和操作。如果结果的所有位全为1(即反码为0),说明数据没有出错;否则,说明传输过程中出现了错误,接收方可以丢弃该报文段(或者交给应用程序并附带警告)。
用一个简单的比喻来理解:检验和就像快递包装上的封条。寄件时贴上封条,收件时检查封条是否完好。如果封条破了,说明包裹可能被动过手脚。当然,封条不能保证100%发现问题,但总比什么都没有好。
为什么UDP需要检验和?

你可能会问:数据链路层不是已经有差错检测了吗?为什么UDP还要自己搞一个检验和?这背后涉及一个重要的设计理念------端到端原则(End-to-End Principle)。
端到端原则的核心思想是:只有在通信的端点才能真正保证数据的正确性。原因有以下几点:
- 数据在从源到目的的传输过程中,可能经过多个链路和路由器。虽然某些链路(如以太网)有自己的差错检测机制,但并非所有链路都有。
- 即使每个链路都有差错检测,数据在路由器内部的内存中处理时也可能出错------比如从网卡到内存的DMA传输过程中发生比特翻转。
- 某些链路的差错检测可能不够强,漏过了错误。
因此,UDP在运输层(端点处)提供检验和,是一种"最后一道防线"的保障。即使中间环节出了差错,端点的检验和也能大概率检测到。这正是端到端原则的体现:可靠性最终还是要靠端点自己来保证。
Internet检验和 vs CRC
UDP使用的这种检验和被称为Internet检验和 (Internet Checksum)。它的优点是简单------只需要加法和取反,用软件实现非常容易,不需要额外的硬件支持。但它的缺点也很明显:差错检测能力不够强。
相比之下,CRC(Cyclic Redundancy Check,循环冗余校验)是一种更强的差错检测方法。CRC使用多项式除法来生成校验码,能够检测更多类型的错误模式,广泛应用于数据链路层(如以太网的帧校验序列FCS)。但CRC的计算比Internet检验和复杂,通常需要硬件支持。
所以这里有一个设计权衡:UDP选择了简单的Internet检验和,虽然检测能力不如CRC,但对于运输层来说已经够用了。更强的差错检测可以留给数据链路层去做。这又是一个"分层"思想的体现------每层做好自己的事,层与层之间互相补充。
本节核心总结

回顾本节内容,UDP的知识可以归纳为以下几个要点:
- UDP是什么:一个无连接的、不可靠的运输层协议,追求简单和速度。
- UDP的核心特征:无连接(不需要握手)、不可靠(不保证交付)、无流量控制、无拥塞控制、首部开销小(仅8字节)。
- UDP的应用场景:DNS、SNMP、实时多媒体、在线游戏等对速度敏感、对丢包不敏感的应用。
- 报文段结构:4个字段的首部(源端口、目的端口、长度、检验和),各2字节,共8字节;之后是应用数据。
- 检验和机制:通过16位字的反码求和计算检验和,用于检测传输过程中的比特错误。
- 端到端原则:即使下层有差错检测,端点仍需自己提供检验和,因为错误可能发生在任何环节。
- Internet检验和 vs CRC:检验和简单但检测能力有限,CRC更强但更复杂,UDP选择了简单。
结语
UDP教会我们一个道理:在工程设计中,简单本身就是一种力量。UDP把"什么都不管"做到了极致,反而成就了它在实时应用领域的不可替代性。没有连接建立的等待,没有拥塞控制的减速,没有重传的延迟------就是纯粹的"发就完了"。
当然,UDP的"简单"也意味着它把可靠性问题甩给了应用层。如果应用需要可靠传输,就得自己在应用层实现重传、序号等机制。这就引出了下一个问题:如果我们既想要可靠传输,又想要它自动处理好各种复杂情况,该怎么办?答案就是下一节的主角------可靠数据传输(Reliable Data Transfer)。让我们继续往下看!