在之前的文章中,介绍了DelimiterBasedFrameDecoder(基于特殊符号的编码器)和FixedLengthFrameDecoder(定长编码器)的用法.这篇文章主要是介绍使用LengthFieldBasedFrameDecoder解码器自定义协议.通常,协议的格式如下:
通常来说,使用ByteToMessageDocoder这个编码器,我们要分别解析出Header,length,body这几个字段.而使用LengthFieldBasedFrameDecoder,我们就可以直接接收想要的一部分,相当于在原来的基础上包上了一层,有了这层之后,我们可以控制我们每次只要读想读的字段,这对于自定义协议来说十分方便.
1. LengthFieldBasedFrameDecoder的定义
|
|
- 在上述的代码中,调用父类的方法,实现截取到自己想要的字段.
2. 协议实体的定义
|
|
3.服务端的实现
|
|
关于
LengthFieldBasedFrameDecoder
的各个字段的头特别意义,可以参考这篇文章(http://www.voidcn.com/article/p-gzqzzsyz-bqy.html),在这里,我们只需要掌握maxFrameLength: 帧的最大长度
lengthFieldOffset length: 字段偏移的地址
lengthFieldLength length;字段所占的字节长
lengthAdjustment: 修改帧数据长度字段中定义的值,可以为负数 因为有时候我们习惯把头部记入长度,若为负数,则说明要推后多少个字段
initialBytesToStrip: 解析时候跳过多少个长度
failFast; 为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异只需要把
MyProtocolDecoder
加入pipeline中就可以.但是得在Handler之前.
- 服务端Hanlder1234567891011121314public class ServerHandler extends ChannelInboundHandlerAdapter {public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {MyProtocolBean myProtocolBean = (MyProtocolBean)msg; //直接转化成协议消息实体System.out.println(myProtocolBean.getContent());}public void channelActive(ChannelHandlerContext ctx) throws Exception {super.channelActive(ctx);}}* 服务端Handler没什么特别的地方,只是输出接收到的消息
5. 客户端和客户端Handler
|
|
客户端Handler
|
|
- 客户端Handler实现发送消息.
客户端编码器
|
|
- 编码的时候,只需要按照定义的顺序依次写入到ByteBuf中.
6. 总结
通过以上的消息,我们能够在客户端和服务端实现自定义协议的交互.其实,在以上的过程中,如果我们把
改成
那么我们就可以直接跳过Header和length字段,从而解码的时候,就只需要对body字段解码就行.其他字段跳过就忽略了.这也就是调用父类的方法的原因(使最后拿到的ByteBuf只有body部分,而没有其他部分).
上面的代码github地址:https://github.com/maskwang520/nettyinaction
参考文章
一起学Netty(九)之LengthFieldBasedFrameDecoder
Netty的LengthFieldBasedFrameDecoder使用