问题简介
TCP是一个“流”协议。所谓流,就是没有界限的一串数据。TCP并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包,可能被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包进行发送。
示意图
模拟
主要代码同https://blog.csdn.net/qq_31473465/article/details/104729562
修改客户端的channelActive代码为
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for (int i = 0; i < 10; i++) {
byte[] req = "QUERY TIME ORDER".getBytes();
ByteBuf firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
ctx.writeAndFlush(firstMessage);
}
}
执行得到,服务端只接受到一次消息
解决方案
由于TCP无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决。
- 消息定长,例:每个报文的大小为固定200字节,如果不够,空位补空格。(FixLengthFrameDecoder)
- 在包尾增加回车换行符进行分割,例如FTP协议。(LineBasedFrameDecoder、DelimiterBasedFrameDecoder)
- 将消息分为消息头和消息体,消息头中包含消息总长度(或消息体总长度)的字段
- 更复杂的应用层协议(需自行开发)