UDP/TCP协议的区别之我的理解
一、 前言
在面试中,无论你从事哪个方向的开发,甚至是测试、运维等,面试官往往会问到一个很普遍的问题:UDP和TCP之间到底有什么区别?
通常,我们都会很轻松的回答:TCP是面向链接的协议,而UDP是免费数据报的协议。这么回答当然是没错,但往往面试官无法给你一个高分,因为这回答也太简单、太常见了!我记得很早以前有一个面试官就在我按上述回答之后问我,能不能再详细一些,而不是网上说的那么简单。
在工作了几年之后,对网络开发也有了一些深入的了解,我觉得应该写篇博客来总结一下了。
二、概念区别
概念上的区别,那肯定就是上面所说的,TCP是面向链接的协议,而UDP是免费数据报的协议。这句话是否完全正确呢?大多数的情况下当然是的,但其实我在这里说个小小的例外,那就是在使用socket编程的时候,当使用UDP时,往往不会使用connect函数。然而其实是可以使用的。当UDP的socket在connect之后,我们在netstat -an中可以看到UDP类型的socket也会显示为ESTABLISHED状态。那么这时候可否认为此UDP的socket为面向链接的流模式呢?也许吧~
三、使用区别
第三点的区别,我认为是最大的区别。
1、协议区别
在使用TCP的时候,我们都知道,TCP由于是数据流,所以存在所谓的“粘包”问题(据说这是中国程序员创造的概念)。具体来说,就是在TCP socket收的一段,读取一段数据,可能会读出发送端连续发送多次的数据。这是因为TCP的nagle算法或由于TCP接收端未及时收取数据,发送端缓冲区会合并数据一起发送。而UDP不存在这个问题,发送端发送多少次,接收端就需要读取多少次数据,即使发送端例如发送500字节,而接收端recv时指定只接受300字节,那剩下的200字节也会被丢弃。
这样就会造成协议设计上的区别:在使用TCP的时候,通常会在协议上增加数据包分隔符,或者是数据包长度,使得TCP接收端可以正常区别数据包。而UDP则不需要。
另外,TCP在发送时没有大小限制,而UDP由于包头中有2个字节的长度字节,则有65535的大小限制。
2、程序设计区别
另外,由于TCP存在发送缓冲区,数据需要填充到缓冲区中,当socket设置为阻塞模式时,若缓冲区无数据空间可填充,则在发送时会阻塞;若为非阻塞模式,则会返回EWOULDBLOCK错误。当TCP缓冲区例如只剩300字节空间时,应用程序往socket中写入500字节时,则会返回300,应用程序再次写入200时,则会重复上述错误或阻塞。
而UDP不存在这个问题。UDP即使将socket设置为阻塞模式,在发送时也不会阻塞。因为不存在像TCP那样的发送缓冲区,UDP发送只是将数据复制到内核中,如果数据超过了UDP的大小,则直接返回错误。
正因为有上述的区别,在程序设计时,TCP往往设置为队列方式,将各线程的数据推入队列,在一条线程中将数据发送给TCP的socket,不这么做的话,很可能会有线程安全问题。这是因为TCP的socket写入时,需要有个循环判断返回值,此时,如果有多个线程同时写入socket,即使发送是系统调用可以保证线程安全,但在判断返回值时,很可能产生内核调度;而UDP则不需要,因为socket的写入操作是系统调用,且UDP本身就不保证数据的顺序到达,每次写入一定是一次性写完不需要判断返回值,所以不需要进行线程安全的自己判断。
3、性能区别
TCP由于需要保证数据的保证性和顺序,每条链接都有一个socket由内核管理,且需要3次握手、4次挥手等操作。且在4次挥手时,还会产生TIME_WAIT的状态,故TCP的性能肯定是比UDP差很多的。据我所知,很多大厂已经在研究UDP的可靠性传输,这样可以避免3次挥手带来的延迟问题,尤其是在SSL情况下,UDP可以在2次握手的情况下,完成之前TCP三次握手加SSL四次握手,大大缩短的延迟时间。比如Google就是在Chrome浏览器中内置了QUIC协议,当我们访问Google、Youtube等网站时,是使用的UDP协议而不是TCP。
4、功能区别
这个主要是UDP可以进行多播或广播,而TCP只能一对一的进行数据传输。另外UDP可以进行P2P打洞而突破NAT,但TCP由于三次握手的存在而很难打通。我也听说过有高手使用TCP打洞并有很高的成功率,不过毕竟是少数。
我马上要入职爱奇艺了的基础网络部门了,希望也能在网络方面有更深入的理解~以后有了新的领悟再来更新这篇博客。