Netty对JBoss Marshalling序列化的解决粘包/半包问题的编解码方案

解码工具:MarshallingDecoder

编码工具:MarshallingEncoder

  • 代码

1.MarshallingSerializeServer:服务器

/**
 * @author pdc
 */
public class MarshallingSerializeServer {

    public void bind(int port) throws Exception {
        //配置服务端的NIO线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //配置Marshalling序列化解码工具
                            ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
                            ch.pipeline().addLast(new MarshallingSerializeServerHandler());
                        }
                    });
            //绑定端口,同步等待成功
            ChannelFuture f = b.bind(port).sync();
            //等待服务端监听端口关闭
            f.channel().closeFuture().sync();
        } finally {
            //优雅退出,释放线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new MarshallingSerializeServer().bind(port);
    }
}

2.MarshallingSerializeServerHandler

/**
 * @author pdc
 */
public class MarshallingSerializeServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //接收客户端发送过来的消息,其中经过前面解码工具的处理,将字节码消息自动转换成了UserInfo对象
        UserInfo req = (UserInfo) msg;
        System.out.println("received from client:" + req.toString());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

3.MarshallingSerializeClient:客户端

/**
 * @author pdc
 */
public class MarshallingSerializeClient {

    public void connect(int port, String host) throws Exception {
        // 配置客户端NIO线程组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            //配置Marshalling序列化编码工具ObjectEncoder
                            ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
                            ch.pipeline().addLast(new MarshallingSerializeClientHandler());
                        }
                    });
            ChannelFuture f = b.connect(host, port).sync();
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new MarshallingSerializeClient().connect(port, "127.0.0.1");
    }
}

4…MarshallingSerializeClientHandler

/**
 * @author pdc
 */
public class MarshallingSerializeClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        //channel建立之后,向服务端发送消息,需要注意的是这里写入的消息是完整的UserInfo对象
        UserInfo user = UserInfo.newBuilder()
                .name("pdc")
                .userId(10000)
                .email("[email protected]")
                .mobile("155****8525")
                .remark("remark info").build();

        ctx.writeAndFlush(user);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

5.MarshallingCodeCFactory:序列化编解码工具类

/**
 * 序列化编解码工具类
 * @author pdc
 */
public class MarshallingCodeCFactory {

    // 首先通过Marshalling序列化工厂类, 参数serial标识创建的是java序列化工厂对象
    private final static MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
    // 创建了MarshallingConfiguration对象,配置了版本号为5
    private static final MarshallingConfiguration configuration = new MarshallingConfiguration();

    static {
        configuration.setVersion(5);
    }

    /**
     * 创建解码器MarshallingDecoder
     */
    public static MarshallingDecoder buildMarshallingDecoder() {
        // 根据marshallerFactory和configuration创建provider
        UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
        // 构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
        return new MarshallingDecoder(provider, 1024 * 100);
    }

    /**
     * 创建编码器MarshallingEncoder
     */
    public static MarshallingEncoder buildMarshallingEncoder() {
        MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
        // 构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
        return new MarshallingEncoder(provider);
    }
}
  • 运行:

先运行MarshallingSerializeServer的main,再运行MarshallingSerializeClient的main即可

猜你喜欢

转载自blog.csdn.net/qq_41594698/article/details/94608856