1. 编码器解码器的引入
通常情况下,当我们得到ByteBuf情况下,我们如果得解码得到我们想要的消息,通常情况下是如下这样处理
这样的一个弊端是,每次InBoundHandler的channelRead读取数据时候,都要读到一个数组中,然后转化成我们想要的数据.这样太过于麻烦了.如果我们直接将msg转化成我们想要的类型,这就非常的快捷.这就是解码器的目的.
2. DelimiterBasedFrameDecoder解码器
DelimiterBasedFrameDecoder解码器用来解码以自定义特殊字符串结尾的消息,例如以”#“结尾的消息,每遇到一个以”#“字符串,则触发channelRead()读取数据.
服务端代码
- 以上定义了DelimiterBasedFrameDecoder,并且添加到Pipeline中.
- 同样引入了StringDecoder编码器,这个编码器的作用是把读到的内容作为整个字符串,不分开.
- 以上过程中需要注意DelimiterBasedFrameDecoder,StringDecoder加入到 PipeLine中的顺序.
先加入DelimiterBasedFrameDecoder,后加入StringDecoder.表明是以”#“作为结束符号,然后StringDecoder把这个结束的字符串作为读取成功的.
服务端Handler
- 这里服务端传给客户端同样采用以”#“作为分隔符号,然后读取每个字符串.
客户端代码
- 客户端的逻辑和服务端差不多
客户端Handler
客户端的Handler与服务端的Handler差不多.
客户端运行结果如图
客户端运行结果如图
结果分析,客户端首先发动”aaaa”字符串(以”#“分隔),然后服务端发动hello给客户端.接着客户端发送剩下的”aa”给服务端,服务端发动”hello”给客户端.
- 编码器,解码器的编程示范
接下来实现的是一个把一个字节转化int的编解码器.
解码器实现如下12345678910111213public class ByteToIntegerDecoder extends ByteToMessageDecoder {protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {if(in.readableBytes()>=4){int n = in.readInt();System.out.println("decode meg is "+n);out.add(n);}}}
注意最后需要List中去
编码器实现如下12345678public class IntegerToByteEncoder extends MessageToByteEncoder<Integer>{protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception {System.out.println("encode message is msg"+msg);out.writeInt(msg);}}上面的编码器实现的是把int转化成字节码.
总结:
通过以上的方式,我们能够很快定义一个编码器和解码器,来处理传输过程中的数据转换.对于Tcp的粘包问题,将在下面讲到.
上面的代码github地址:https://github.com/maskwang520/nettyinaction
参考文章: