netty传输对象使用protostuff实现序列化操作

序列化

序列化即是将java对象转为二进制数据流,在网络中的数据传输就要实现数据的序列化和反序列化。

实现序列化可以使用JDK自带的方式:实现Serializable接口即可,操作很简单。
但是这种方式的确定就是效率很低。
所以,这时我们可以使用一些第三方的序列化方式提高效率,这里使用protostuff

首先导入依赖

<dependency>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-java</artifactId>
     <version>2.5.0</version>
 </dependency>

实体

public class Person {
    String name;
    int id;
    String email;
}

proto描述文件的编写

语法
3.5的语法跟以前的protobuf语法有很大的变化,详细的可以参考官方文档,
地址:https://developers.google.com/protocol-buffers/docs/proto3
这里有一个中文翻译的文档
地址:http://blog.csdn.net/u011518120/article/details/54604615

重点注意的地方有这么几点:句法申明、数据类型

客户端

public class Client {

    public static class ProtoBufClient {
        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 {

                                // 用来添加报文长度字段
                                ch.pipeline().addLast(
                                        new ProtobufVarint32LengthFieldPrepender());

                                //添加 ProtobufEncoder 进行序列化将实体类编码为字节
                                ch.pipeline().addLast(new ProtobufEncoder());

                                //添加自己的业务Handler
                                ch.pipeline().addLast(
                                        new ProtoBufClientHandler());
                            }
                        });

                ChannelFuture f = b.connect(host, port).sync();
                f.channel().closeFuture().sync();
            } finally {
                // 优雅退出,释放NIO线程组
                group.shutdownGracefully();
            }
        }

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


}

客户端处理器

public class ProtoBufClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("准备生成数据===========>");

        //生成实体类
        PersonProto.Person.Builder builder = PersonProto.Person.newBuilder();
        builder.setName("CemB");
        builder.setId(1);
        builder.setEmail("[email protected]");
        System.out.println("发送数据===========>" + builder.getName());

        //写往服务端,由编码器进行编码
        ctx.writeAndFlush(builder.build());
    }

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

服务端

public class ProtoBufServer {
    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)
                    //初始化服务端可连接队列为100个
                    .option(ChannelOption.SO_BACKLOG, 100)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {

                            //添加 ProtobufVarint32FrameDecoder 以分离数据帧
                            ch.pipeline().addLast(
                                    new ProtobufVarint32FrameDecoder());

                            //添加 ProtobufDecoder 反序列化将字节解码为实体
                            ch.pipeline().addLast(new ProtobufDecoder(
                                    PersonProto.Person.getDefaultInstance()
                            ));

                            //添加自己业务Handler
                            ch.pipeline().addLast(new ProtoBufServerHandler());
                        }
                    });

            // 绑定端口,同步等待成功
            ChannelFuture f = b.bind(port).sync();

            System.out.println("init start");
            // 等待服务端监听端口关闭
            f.channel().closeFuture().sync();
        } finally {
            // 优雅退出,释放线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

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

服务端处理器

public class ProtoBufServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        //将上一个handler传入的数据强制转型,因为已经反序列化了
        PersonProto.Person req = (PersonProto.Person) msg;
        System.out.println("收到数据:name=" + req.getName() + ",email=" + req.getEmail());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        if (cause instanceof IOException) {
            System.out.println("远程客户端强迫关闭了一个现有的连接。");
        }
        ctx.close();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_28822933/article/details/83626460