TCP 以流的方式进行数据传输, 上层的应用协议为了对消息进行区分, 往往采用如下 4 中方式.
- 消息长度固定, 累计读取到长度总和为定长 LEN 的报文后, 就认为读到了一个完整的消息; 将计数器置位, 重新开始读取下一个数据报;
- 将回车换行符作为消息结束符, 例如 FTP 协议, 这种方式在文本协议中应用比较广泛.
- 将特殊的分隔符最为消息的结束标志, 回车换行符就是一种特殊的结束分隔符;
- 通过在消息头中定义长度字段来标识消息的总长度.
Netty 对上面 4 种应用做了统一的抽象, 提供了 4 种解码器来解决对应用的问题.
之前我写了 LineBasedFrameDecoder 解码器的使用, 今天开始学习如何使用 DelimiterBasedFrameDecoder
和 FixedLengthFrameDecoder
.
DelimiterBasedFrameDecoder 应用开发
通过对 DelimiterBasedFrameDecoder
的使用, 我们可以自动完成以分隔符作为码流结束标识的消息的解码.
还是修改 initChannel
方法
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new TimeServerHandler());
我们使用 $_
作为分隔符, 创建 DelimiterBasedFrameDecoder
对象, 将其加入到 ChannelPipeline
中. DelimiterBasedFrameDecoder
有多个构造方法, 这里我们传递两个参数: 第一个 1024 表示单条消息的最大长度, 当达到该长度后仍然没有检查到分隔符, 将抛出 TooLongFrameException
异常, 防止由于异常码流缺失分隔符导致的内存溢出, 这是 Netty 解码器的可靠性保护; 第二个参数就是分隔符缓冲对象.
由于我们设置DelimiterBasedFrameDecoder
过滤掉了分隔符, 所以返回给客户端时需要在请求消息尾部拼接分隔符$_
.
FixedLengthFrameDecoder 应用开发
FixedLengthFrameDecoder
是固定长度解码器, 它能够按照指定的长度对消息进行自动解码.
ch.pipeline().addLast(new FixedLengthFrameDecoder(10));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new TimeServerHandler());
利用 FixedLengthFrameDecoder
解码器, 无论一次接收到多少数据报, 他都会按照构造函数中设置的固定长度进行解码, 如果是半包消息, FixedLengthFrameDecoder
会缓存半包消息并等待下个包到达后进行拼包, 直到读取到一个完整的包.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。