我们知道TCP和UDP是使用不同的套接字标识符来实现分用和复用,TCP使用四元组(源IP,源端口,目标IP,目标端口)来标识一个TCP套接字,而UDP使用的是二元组(目的ip,目标端口)来标识。
在这里我们不妨思考一个问题,为什么TCP要用四元组来标识,而UDP使用二元组呢。
假设TCP使用的是二元组来区别不同的TCP套接字,那么会出现什么情况呢?
1,显然使用(目的ip,目标端口)这种二元组的情况并不能唯一标识这个socket
首先,我们知道TCP是面向连接的传输协议,对于每一个建立的连接都会在TCP服务端有一个对应的socket来管理这个连接(原本这是个四元组标识这个socket),因为可能存在这样一种情况: 由多个访问同一台服务器的客户端发起TCP连接的目的ip一致,目标端口也一致,因为没有源ip和源端口,所以服务端无法知道TCP缓冲区中的多个包分别来自哪个源主机,从而导致无法拆包。这就解释了为什么TCP套接字要使用四元组而不是二元组了。
2,使用二元组无法解决粘包问题,why?
其次,TCP和UDP是不同的,TCP是流式协议,UDP是数据报协议,他们内部实现的机制很大不同。表现在工程实践中就是TCP有粘包的问题,而UDP没有,它有消息边界。
产生粘包的几种情况:
(1)TCP粘包是因为当我们使用send的时候,并不会马上发送,为了网络优化,系统内核会将消息写入发送的缓冲区中,当时钟超时或者缓冲区满的时候才会打包发送,这就会发生多次发送的数据在打包在一个报文中产生粘包现象,
(2)另外在接收方收到的数据都会缓存在接收缓冲区中,这样同样会导致收取的时候有粘包现象,在使用四元组标识tcp的时候,粘包问题可以通过拆包来解决。
但是:
由此可以想象,如果TCP使用的是二元组会导致什么现象,不同的具备相同源端口的用户,所产生的数据包会经由同一个socket,因为标识相同,无法区分哪个包属于哪台主机,那么这时产生的粘包就无法解决。而UDP是数据报协议,它会尽快将上层应用的信息立刻打包并发送(无需发送缓冲区),而服务端每次读取一个数据包。这就解释为什么UDP不会产生粘包的问题。