TCP以流的方式进行数据传输,上层的应用协议为了对消息进行区分,可以采用如下方式:
(1)消息长度固定,累计读取到长度总和为定长LEN的报文后,就认为读取到了一个完整的消息;将计数器置位,重新开始读取下一个数据报;
(2)将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛;
(3)将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的结束分隔符;
(4)通过在消息头中定义长度字段来标识消息的总长度。
Netty对上面4种方式做了统一的抽象,提供了4种解码器来解决对应的问题,使用起来非常方便。有了这些解码器,用户不需要自己对读取的报文进行人工解码,也不需要考虑TCP的粘包和拆包。
DelimiterBasedFrameDecoder
:可以自动完成以分隔符做结束标志的消息的解码FixedLengthFrameDecoder
:可以自动完成对定长消息的解码
它们都能解决TCP粘包/拆包导致的读半包问题。
DelimiterBasedFrameDecoder
应用开发
Echo服务:EchoServer
接收到EchoClient
的请求消息后,将其打印出来,然后将原始消息返回给客户端,消息以“$_
”作为分隔符。
DelimiterBasedFrameDecoder
服务端开发
DelimiterBasedFrameDecoder
客户端开发
运行结果
服务端:
客户端:
使用DelimiterBasedFrameDecoder
可以自动对采用分隔符做码流结束标识的消息进行解码。
本例程运行10次的原因是模拟TCP粘包/拆包,在笔者的机器上,连续发送10条Echo请求消息会发生粘包,如果没有DelimiterBasedFrameDecoder
解码器的处理,服务端和客户端程序都将运行失败。
测试不适用DelimiterBasedFrameDecoder
的情况
将服务端的DelimiterBasedFrameDecoder
注释掉:
运行结果:
由于没有分隔符解码器,导致服务端一次读取了客户端发送的所有消息,这就是典型的没有考虑TCP粘包导致的问题。