Netty中对象的序列化,反序列化

来源:互联网 发布:fcn网络结构 编辑:程序博客网 时间:2024/06/03 20:15

之前写的nettydemmo都是传递字符串的,而在真实使用的时候我们传的都是对象,然后写序列化方法进行序列化和返序列化,在netty中对序列化和返序列化都提供了相应的接口,而且netty也支持很多的序列化方式,但这里先提供java的序列化实现方式。


一、java序列化方式

package com.decode;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;/** * Java序列化工具 *  * @author whd * @date 2017年11月6日 上午9:24:35 */public class Utils {public byte[] encodes(Object obj) throws IOException {ByteArrayOutputStream out = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(out);oos.writeObject(obj);oos.flush();oos.close();byte[] bytes = out.toByteArray();return bytes;}public Object decode(byte[] bytes) throws IOException, ClassNotFoundException {// 对象返序列化ByteArrayInputStream in = new ByteArrayInputStream(bytes);ObjectInputStream inn = new ObjectInputStream(in);Object obj = inn.readObject();return obj;}/** * byte to buf *  * @param bytes * @return */public ByteBuf getBufFromByte(byte[] bytes) {ByteBuf buf = Unpooled.copiedBuffer(bytes);return buf;}/** * buf to byte *  * @param buf * @return */public byte[] getByteFromBuf(ByteBuf buf) {int size = buf.readableBytes();byte[] bytes = new byte[size];buf.readBytes(bytes);return bytes;}}


二、Netty中提供的序列化,返序列化接口

1、Encoder(编码)

package com.rpc;import com.decode.Utils;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.MessageToByteEncoder;/** * netty中的编码 *  * @author whd * @date 2017年12月3日 下午7:43:23 */public class Encoder extends MessageToByteEncoder<Object> {/** * 我们知道在计算机中消息的交互都是byte 但是在netty中进行了封装所以在netty中基本的传递类型是ByteBuf */@Overrideprotected void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {Utils util = new Utils();byte[] bytes = util.encodes(in);out.writeBytes(bytes);}}

2、Decoder(解码)

package com.rpc;import java.util.List;import com.decode.Utils;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.ByteToMessageDecoder;/** * 解码 *  * @author whd * @date 2017年11月6日 下午1:56:45 */public class Decoder extends ByteToMessageDecoder {private static final int LENGTH = 4;/** * 解码时传进来的参数是ByteBuf也就是Netty的基本单位,而传出的是解码后的Object */@Overrideprotected void decode(ChannelHandlerContext arg0, ByteBuf in, List<Object> out) throws Exception {Utils util = new Utils();int size = in.readableBytes();// 这里判断大小是为了tcp的粘包问题,这个之后再单独学习if (size > Decoder.LENGTH) {byte[] bytes = util.getByteFromBuf(in);Object info = util.decode(bytes);out.add(info);}}}

注意netty的4.+版本和5.0版本区别还是有点大所以在使用的时候要注意一下,这里使用的是netty的5.0版本!!!


OK这样编码解码OK了,在netty中使用编码解码很简单,之前说过了netty对channel中的消息的处理是链式也就是channelPipeline ,所以在我们实现了编解码之后使用时直接添加到channelpipeline中就OK了:

客户端channelpipeline:

private class InitializerChannel extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new Encoder());pipeline.addLast(new Decoder());pipeline.addLast(new ClientHandler());}}

服务端channelpipeline:

private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline cp = ch.pipeline();cp.addLast(new Decoder());cp.addLast(new Encoder());cp.addLast(new ServerHandler());}}
编码解码流程:

client Application 将Object写出到netty的channel,然后channelPipeline 链式按照配置的将Object转化为byte 写到tcp缓存,然后网络传出

服务端从服务端Tcp缓存读取客户端传递过来的byte流,这时就会从tcp缓存进入serverApplication 这时在进入netty的channelPipeline 首先要做的就是将byte解码为Object,使用的就是我们在pipeline中配置的解码器,这样我们在channelRead()方法中获取的就是解码后的Object了,可以直接转化为我们需要的对象来处理,这样就很方便!

从服务端响应消息到客户端也是一样的流程!