UDP为什么能如此直接呢?其实是因为它设计简单,想复杂起来都没办法。
在UDP协议头中,只有端口号、包长度和校验码等少量信息,总共就8个字节。
小巧的头部给它带来了一些优点。
- 由于UDP协议头长度还不到TCP头的一半,所以在同样大小的包里,UDP包携带的净数据比TCP包多一些。
- 由于UDP没有Seq号和Ack号等概念,无法维持一个连接,所以省去了建立连接的负担。这个优势在DNS查询中体现得淋漓尽致。
当然简单的设计不一定是好事,更多的时候会带来问题。
1、UDP不像TCP一样在乎双方MTU的大小。它拿到应用层的数据之后,直接打上UDP头就交给下一层了。那么超过MTU的时候怎么办?在这种情况下,发送方的网络层负责分片,接收方收到分片后再组装起来,这个过程会消耗资源,降低性能。
2、UDP没有重传机制,所以丢包由应用层来处理。如下面的例子所示,某个写操作需要6个包完成。当基于UDP的写操作中有一个包丢失时,客户端不得不重传整个写操作(6个包)。相比之下,基于TCP的写操作就好很多,只要重传丢失的那1个包即可。
基于UDP的NFS写操作
基于TCP的NFS写操作
也许从这个例子你还感受不到明显的差别,试想一下,在高性能环境中,个写操作需要数十个包来完成,UDP的劣势就体现出来了。
3、分片机制存在弱点,会成为黑客的攻击目标。接收方之所以知道什么时候该把分片组装起来,是因为每个包里都有"More fragments"的flag。1表示后续还有分片,0则表示这是最后一个分片,可以组装了。如果黑客持续快速地发送flag为1的UDP包,接收方一直无法把这些包组装起来,就有可能耗尽内存。
关于UDP就简单介绍这么多。虽然我觉得这个协议实在没多少可谈的,但关于UDP和TCP的争论一直是某些论坛的热门话题。了解了UDP的工作方式,也算学会一门伪装成大牛的手艺。下次再有人宣称"UDP的性能比TCP更好”时,你可以不紧不慢地告诉他,“也不尽然,我来给你举一个NFS丢包的例子……。