TCP粘包/拆包问题和Netty的解决方案
什么是TCP协议?
TCP(Transmission Control Protocol传输控制协议)是Internet协议组的主要协议之一。起源于初始的网络实现,补充了IP协议。因此通常称为TCP/IP协议。TCP在运行在IP通信网络的应用程序之间提供稳定的、有序的和错误检查的8字节流分发功能。—— from wiki
什么是TCP的粘包和拆包问题?
TCP是一个“流”协议,所谓流,就是没有边界的一串数据。TCP底层不了解业务数据的含义,只是按照缓冲区的情况进行包的划分,那么业务上一个完整的数据包有可能被划分成多个包发出,也可能多个包被合并成一个数据包发出,这就是TCP的粘包和拆包问题。
如何解决粘包和拆包问题?
TCP不知道数据包的业务含义,所以只能通过上层协议栈的设计来结局,主流方案:
定长消息,消息长度是固定的,不够的进行补齐
特殊字符分隔,如FTP协议在包尾添加换行符进行分隔
将消息分为消息投和消息体,消息头中包含消息的总长,如前4个字节表示整个消息的长度(最灵活和常用的方案)
Netty对粘包和拆包问题的处理
Netty对解决粘包和拆包的方案做了抽象,提供了一些解码器(Decoder)来解决粘包和拆包的问题。如:
LineBasedFrameDecoder:以行为单位进行数据包的解码
DelimiterBasedFrameDecoder:以特殊的符号作为分隔来进行数据包的解码
FixedLengthFrameDecoder:以固定长度进行数据包的解码
LenghtFieldBasedFrameDecode:适用于消息头包含消息长度的协议(最常用)
所以对使用Netty进行网络读写的程序,可以直接使用这些Decoder来完成数据包的解码。
由于业务程序的复杂性,可能协议也非常复杂。对于高并发、大流量的系统来说,每个数据包都不应该传输多余的数据(所以补齐的方式肯定不可取),LenghtFieldBasedFrameDecode更适合这样的场景。
LenghtFieldBasedFrameDecode提供了灵活的配置来支持业务消息的解码:
实际生产环境中更多是采用自定义的协议,并且编写自己的Decoder类(一般继承LenghtFieldBasedFrameDecode)来完成业务包的解码。