TCP、UDP
TCP粘包拆包
为什么会有TCP粘包?应用层是如何解决TCP粘包的问题?
什么是TCP粘包
TCP粘包就是指发送方发送的若干个数据包到达接收方时粘成了一包,从接受缓冲区看,若干个数据包首位相连,好像是粘在了一块儿。TCP粘包的原因可能是来自发送方,也可能来自接收方。
TCP粘包的原因
- 发送方的原因
TCP默认使用Nagle算法(用于减轻网络负担,提高数据传输的效率),而Nagle算法主要工作有这么两个:
- 只有上一个分组得到确认,才会发送下一个分组的数据包
- 收集多个小分组,累计数据量,在一个确认到来后一块发送
发送方由于使用了Nagle算法,才会导致TCP粘包的现象
- 接收方的原因
一般情况下,接收方收到数据包时,并不会立马交付给应用层进行处理,而是放在缓冲窗口中,然后应用程序再从缓冲窗口中读取收到的分组。如果应用程序的读取速度远小于数据的缓存速度,那么就会有多个包被缓存在窗口中,此时应用程序就可能会读取到首位粘在一起的数据包
如何解决TCP粘包
对于发送方,可以通过关闭Nagle算法来解决
对于接收方,只能依靠应用层来解决
对于应用程序,一般有两种方法来区别一大坨的数据分别由哪个分组构成:
- 格式化数据:每条数据都有固定的格式,例如大名鼎鼎的Redis在数据交互时就用
\n
来区分每一个数据分组 - 发送长度:发送每条数据时,将数据的长度一并发送,例如HTTP协议中的
Content-Length
字段
UDP有木有粘包问题
TCP采用了基于流的传输,基于流的传输不认为消息是一条一条的,是无保护消息边界的
而UDP则是面向消息传输的,是有保护消息边界的,接收方只能一次只能接受一条独立的消息,所以不存在粘包问题
TPC异常
如果客户端进程崩溃,客户端的进程在发生奔溃时,内核会发送FIN报文,与服务端进行四次挥手
如果客户端主机宕机,客户端不会发送FIN报文,后续情况需要根据服务端的行为来判断
- 如果服务端会发送数据,由于客户端已经宕机,服务端收不到响应报文,于是会进行超时重传,当重传总间隔时长超过一定阈值后,会断开TCP连接
- 如果服务端不会发送数据,则需要看看服务端是否开启了TCP keepalive机制
- 如果开启了TCP keepalive机制,服务端通过发送探测报文发现客户端已经消亡,则会断开自身的TCP连接
- 如果没有开启,服务端的TCP连接会一直存在,并且保持着ESTABLISHED状态
HTTP Keep-Alive和TCP Keepalive
HTTP Keep-Alive
HTTP协议基于TCP传输协议实现,采用请求、应答模式进行信息交互。也就是说,每一次的数据传输都要经历这四个过程:建立TCP连接 --> 请求数据资源 --> 响应数据资源 --> 断开TCP连接(即HTTP短连接)
但现如今,一个HTML页面就可能包含了上百个数据资源,也就是说至少得建立几百个TCP连接才能把一个网页加载出来。如此浮躁的时代,如此夸张的网络延迟,用户体验肯定异常糟糕
一个很直接的想法就是所有的请求应答资源都共用一个TCP连接,这样就省去了很多建立、断开TCP连接的时间。而在实际应用中,就是使用HTTP Keep-Alive实现这个功能的,可以使用同一个TCP连接来发送和接收多个HTTP请求/应答,避免连接建立和释放的开销,即HTTP长连接
HTTP长连接的一个特点就是:只要一端没有明确断开连接,就保持TCP连接状态
TCP Keepalive
TCP Keepalive机制就是TCP连接的保活机制,当连接的双方很长一段时间没有通信(进行数据的交互),达到触发TCP保活机制的条件,那么内核中的TCP协议栈就会发送探测报文
- 如果对端程序正常运行,接收到探测报文后会正常响应,TCP保活时间将被重置
- 如果对端主机宕机(注意不是进程崩溃,因为当操作系统回收崩溃的进程时,会发送FIN报文来断开TCP连接。而主机宕机则是对端不可知的,需要通过保活机制来探测是否是真的宕机),或其他原因导致探测报文无法正常得到响应,重复几次,达到重发阈值后,就报告TCP连接死亡,需要断开该TCP连接
UDP vs TCP
弄清楚UDP和TCP的区别和应用场景,至少要记忆3个区别
- 连接
- TCP要求在发送方和接收方通信之前建立一个TCP连接,是面向连接的协议
- UDP是无连接协议
- 保证数据传输的顺序
- 在TCP中,由于事先建立了一条良好的连接,接收方将顺序地接收数据包
- 而在UDP中,接收方以无序的方式接收数据包
- 可靠性
- 每当接收方通过TCP连接接收到数据包后,都会向发送方发送一个响应包,明确不需要重传这个数据包
- UDP是尽力而为的,只能依赖于高层协议实现可靠传输,例如QUIC协议
- 错误检查
- TCP中有广泛的错误检查规则,
- 而UDP中只有基本的校验和错误检查技术
- 传输方法
- 在TCP中,数据以字节流的形式传输
- 而在UDP中,数据是以一个一个数据包的形式发送的
- 广播
- TCP不支持广播,因为TCP协议要求发送方和接收方建立一条连接,在发送后断开连接
- UDP支持广播
- TCP和UDP常见使用场景
- TCP:HTTPS、HTTP、SMTP、FTP
- UDP:DNS、视频流、视频电话、语音服务