5、netty的自带的序列化Protocol Buffers和MessagePack的使用示例

注:源代码来自享学课堂,略有修改,学习之后所做笔记,方便回顾,也给大家一个参考

why:

Java序列化仅仅是Java编解码技术的一种

1.网络传输

2.对象持久化

java自带序列化的缺点

1、无法跨语言

2、序列化之后的流太大

3、序列化新能的,耗时长

netty常用的序列化

Netty内置了对JBoss Marshalling和Protocol Buffers的支持

Protocol Buffers

一下只是简化的代码,pipleLine添加ProtobufEncoder、ProtobufDecoder编解码就行,其他的相关文件,请参考protocol使用文档

导入jar

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

客户端

.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());
    }
});

服务端

.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());
}

内置MessagePack,使用MsgPackEncoder序列化

导入jar

<dependency>
     <groupId>org.msgpack</groupId>
     <artifactId>msgpack</artifactId>
     <version>0.6.12</version>
</dependency>

需要被序列化的对象加上@Message注解(一下省略了set/get方法,使用是请自行加上)

@Data
@Message
public class User {
    private String id;
    private String userName;
    private int age;
}

使用MessagePack自定义编解码器

编码器

public class MsgPackEncoder extends MessageToByteEncoder<Object> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out)
            throws Exception {
        MessagePack messagePack = new MessagePack();
        byte[] raw = messagePack.write(msg);
        out.writeBytes(raw);
    }
}

解码器:这里不使用ByteToMessageDecode,而使用MessageToMessageDecoder,是应为把bytebuf当做message来处理的

public class MsgPackDecoder extends MessageToMessageDecoder<ByteBuf> {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg,
                          List<Object> out) throws Exception {
        int length = msg.readableBytes();
        byte[] array = new byte[length];
        msg.getBytes(msg.readerIndex(),array,0,length);
        MessagePack messagePack = new MessagePack();
        out.add(messagePack.read(array,User.class));

    }
}

客户端主函数

public class MyClient {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();

        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .remoteAddress(new InetSocketAddress("127.0.0.1",8080))
                .handler(new MyChannelInit());

        ChannelFuture future = bootstrap.connect().sync();
        future.channel().closeFuture().sync();

        group.shutdownGracefully().sync();
    }

    private static class MyChannelInit extends ChannelInitializer<SocketChannel>{

        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            //粘包,编码
            pipeline.addLast(new LengthFieldPrepender(2));
            //序列化
            pipeline.addLast(new MyMessageEncoder());

            //入站解码
            pipeline.addLast(new LineBasedFrameDecoder(1024));
            //自定义handler,
            pipeline.addLast(new MyClientHandler());
        }
    }
}

客户端handler

public class MyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    private AtomicInteger counter = new AtomicInteger(0);

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        System.out.println("client Accept[" + byteBuf.toString(CharsetUtil.UTF_8)
                + "] and the counter is:" + counter.incrementAndGet());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //还是一个一个发送,接收也是一个一个接收的
        User[] users = makeUsers();
        for (User user : users) {
            ctx.write(user);
        }
        ctx.flush();
    }

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

    /**
     * 生成多个用户对象
     * @return 数组
     */
    private User[] makeUsers() {
        User[] users = new User[10];
        User user;
        for (int i = 0; i < 10; i++) {
            user = new User();
            user.setAge(i);
            String userName = "序列化-" + i;
            user.setUserName(userName);
            users[i] = user;
        }
        return users;
    }
}

服务端主函数

LengthFieldBasedFrame:实际数据包长度 = 长度域中记录的数据长度 + lengthFieldOffset + lengthFieldLength + lengthAdjustment

public class MyServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();

        bootstrap.group(group)
                .channel(NioServerSocketChannel.class)
                .localAddress(new InetSocketAddress(8080))
                .childHandler(new MyServerChannelInit());

        ChannelFuture future = bootstrap.bind().sync();
        future.channel().closeFuture().sync();

        group.shutdownGracefully().sync();
    }

    private static class MyServerChannelInit extends ChannelInitializer<SocketChannel> {

        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            //这里服务器只是给客户端发送简单的字符串消息,所以未加出站编码相关处理

            //入站分理处编码的长度并拿到数据
            pipeline.addLast(new LengthFieldBasedFrameDecoder(65535,0,2,0,2));
            //反序列化
            pipeline.addLast(new MyMessageDecoder());
            //自定义handler
            pipeline.addLast(new MyServerHandler());
        }
    }
}

服务端handler

@ChannelHandler.Sharable
public class MyServerHandler extends ChannelInboundHandlerAdapter {

    private AtomicInteger counter = new AtomicInteger(0);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //将上一个handler生成的数据强制转型
        User user = (User) msg;
        System.out.println("Server Accept[" + user
                + "] and the counter is:" + counter.incrementAndGet());
        //服务器的应答
        String resp = "I process user :" + user.getUserName()
                + System.getProperty("line.separator");
        ctx.writeAndFlush(Unpooled.copiedBuffer(resp.getBytes()));
    }

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

服务端结果

Server Accept[User(id=null, userName=序列化-0, age=0)] and the counter is:1
Server Accept[User(id=null, userName=序列化-1, age=1)] and the counter is:2
Server Accept[User(id=null, userName=序列化-2, age=2)] and the counter is:3
Server Accept[User(id=null, userName=序列化-3, age=3)] and the counter is:4
Server Accept[User(id=null, userName=序列化-4, age=4)] and the counter is:5
Server Accept[User(id=null, userName=序列化-5, age=5)] and the counter is:6
Server Accept[User(id=null, userName=序列化-6, age=6)] and the counter is:7
Server Accept[User(id=null, userName=序列化-7, age=7)] and the counter is:8
Server Accept[User(id=null, userName=序列化-8, age=8)] and the counter is:9
Server Accept[User(id=null, userName=序列化-9, age=9)] and the counter is:10

客户端结果

client Accept[I process user :序列化-0] and the counter is:1
client Accept[I process user :序列化-1] and the counter is:2
client Accept[I process user :序列化-2] and the counter is:3
client Accept[I process user :序列化-3] and the counter is:4
client Accept[I process user :序列化-4] and the counter is:5
client Accept[I process user :序列化-5] and the counter is:6
client Accept[I process user :序列化-6] and the counter is:7
client Accept[I process user :序列化-7] and the counter is:8
client Accept[I process user :序列化-8] and the counter is:9
client Accept[I process user :序列化-9] and the counter is:10

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值