前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Netty】03-实战之序列化与反序列化协议

【Netty】03-实战之序列化与反序列化协议

作者头像
envoke
发布2020-09-17 12:03:15
1.3K0
发布2020-09-17 12:03:15
举报

Netty实战之序列化与反序列化协议

序列化与反序列化概念

序列化

客户端与服务器端通讯,不能将对象进行直接传输的。通讯的本质为流传输,所以,我们可以将对象序列化成流进行传输。

实质:将对象转化为字节的过程

反序列化

服务端接收到序列化过后的对象,需要反序列化后,才能将之转化为对象拿来使用

实质:将字节转换为对象的过程

序列化的模式(两种)

对象持久化概念:将对象转化为字节,存储到硬盘上的过程

网络传输对象概念: 将对象转化为字节的形式(序列化 ),二进制方式发送给服务端,服务端再将字节转换为对象的过程(反序列化),总的过程即为rpc远程通讯

序列化图解
在这里插入图片描述
在这里插入图片描述
什么rpc远程调用

服务器与服务器之间进行通讯

序列化的模式:

对象持久化:将对象转化为字节,存储到硬盘上的操作。

网络对象传输:客户端将对象转化为字节(序列化),再将数据传输到服务端,服务端将数据从字节转化为对象(反序列化)。

序列化有哪几种方式?
  1. 采用JSON序列化进行传输
  2. 使用XML协议进行传输
  3. 使用protoBuf,谷歌自定义的协议
  4. 使用MessagePack进行序列化传输
  5. 大公司开发的自定义协议
MessagePack的使用案例:

这里我们把Json序列化也加入了进来,实际的看下MessagePack和JSON的区别:

代码语言:javascript
复制
 User user = new User(1, "张三", 24);
        // 使用json来序列化
        String userJson = JSON.toJSONString(user);
        System.out.println("fastJson"+ userJson);
        // 使用MessagePack来将对象进行序列化
        MessagePack messagePack = new MessagePack();
        byte[] write = messagePack.write(user);
        Value read = messagePack.read(write);
        System.out.println("MessagePack:" + read);

测试结果为:

MessagePack和JSON序列的区别:

比较项

MessagePack

JSON

示例

[1,“张三”,24]

{“age”:24,“id”:1,“name”:“张三”}

体积

体积小,是将对象的值存入到序列化数组中

体积稍大,以key-value的形式

灵活性

灵活性差,client与server中属性的顺序必须保持一致,否则会出错

灵活性较高

为什么要使用序列化

网络传输采用的是流传输,在Nio和Netty中都采用的是Buffer来进行传输。所以,对象是不能直接进行传输的。需要序列化成字节或者buffer才能继续进行传输

使用MessagePack进行对象实例
添加pom依赖
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>netty-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.12.Final</version>
        </dependency>
        <!-- 序列化组件,更加小巧 -->
        <!-- https://mvnrepository.com/artifact/org.msgpack/msgpack -->
        <dependency>
            <groupId>org.msgpack</groupId>
            <artifactId>msgpack</artifactId>
            <version>0.6.12</version>
        </dependency>
        <!-- 序列化组件:fastJson -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

    </dependencies>

</project>
添加User实体类

要使用MessagePack进行序列化,需要在实体类上加入@Message注解

代码语言:javascript
复制
package com.itmayiedu.entity;

import org.msgpack.annotation.Message;

@Message
public class User {

    private Integer id;
    private String name;
    private Integer age;

    public User() {
    }

    public User(Integer id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}
创建自定义编码器MessagePackEncoder
代码语言:javascript
复制
package com.itmayiedu.code;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.msgpack.MessagePack;

/**
 * 自定义MessagePack编码器
 */
public class MessagePackEncoder extends MessageToByteEncoder {

    protected void encode(ChannelHandlerContext channelHandlerContext, Object msg, ByteBuf byteBuf) throws Exception {
        // messagePack序列化
        MessagePack messagePack = new MessagePack();
        // 采用byteBuf传输
        byteBuf.writeBytes(messagePack.write(msg));
    }
}
创建自定义解码器MessagePackDecoder
代码语言:javascript
复制
package com.itmayiedu.code;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import org.msgpack.MessagePack;

import java.util.List;

/**
 * MessagePackDecoder编码器
 */
public class MessagePackDecoder extends MessageToMessageDecoder<ByteBuf> {

    // 解码器
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception {
        // 定义数组
        final byte[] array;
        // 获取读取长度
        final int length = byteBuf.readableBytes();
        array = new byte[length];
        byteBuf.getBytes(byteBuf.readerIndex(), array, 0, length);
        //mp的read方法将其反序列化为object对象
        MessagePack mp = new MessagePack();
        list.add(mp.read(array));
    }
}
创建自定义解码器NettyServer
代码语言:javascript
复制
package com.itmayiedu.demo;

import com.itmayiedu.code.MessagePackDecoder;
import com.itmayiedu.code.MessagePackEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * 搭建NettyServer
 *
 */
public class NettyServerDemo {
    static final int port = 8080;
    public static void main(String[] args) {
        // 1. 创建两个线程池,分别作为boss线程池和work线程池
        // boss线程池
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        // work线程池
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        // 创建NettyServer
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 将线程池加入到serverBootStrap中              设置为服务端: NioServerSocketChannel.class
        serverBootstrap.group(bossGroup, workGroup).channel(NioServerSocketChannel.class)
        // 添加消息处理
        .childHandler(new ChannelInitializer<SocketChannel>() {
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new MessagePackEncoder());
                ch.pipeline().addLast(new MessagePackDecoder());
                ch.pipeline().addLast(new ServerHandler());
            }
        });
        try{
            ChannelFuture channelFuture = serverBootstrap.bind(port);
            System.out.println("服务端已经启动,port: " + port);
            channelFuture.channel().closeFuture().sync();
        }catch(Exception e) {

        }finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();

        }

    }
}
创建ServerHandler
代码语言:javascript
复制
package com.itmayiedu.demo;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class ServerHandler extends SimpleChannelInboundHandler<Object> {


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

    // 读取消息的方法
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("服务端接收到消息:" + msg);
    }
}
搭建NettyClient
代码语言:javascript
复制
package com.itmayiedu.demo;

import com.itmayiedu.code.MessagePackDecoder;
import com.itmayiedu.code.MessagePackEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.io.IOException;
import java.net.InetSocketAddress;

public class NettyClientDemo {
    public static void main(String[] args) throws IOException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class)
                .remoteAddress(new InetSocketAddress("127.0.0.1", 8080))
                .handler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new MessagePackEncoder());
                        ch.pipeline().addLast(new MessagePackDecoder());
                        ch.pipeline().addLast(new ClientHandler());
                    }
                });
       try{
           ChannelFuture sync = bootstrap.connect().sync();
           sync.channel().closeFuture().sync();
       }catch (Exception e) {

       }finally {
           group.shutdownGracefully();
       }
    }
}
创建ClientHandler
代码语言:javascript
复制
package com.itmayiedu.demo;

import com.itmayiedu.entity.User;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.msgpack.MessagePack;

public class ClientHandler extends SimpleChannelInboundHandler<Object> {


    /**
     * 发送消息的方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        User user = new User(1, "张三", 25);
        ctx.writeAndFlush(user);
    }

    /**
     * 获取消息的方法
     * @param ctx
     * @param msg
     * @throws Exception
     */
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("客户端接收到消息: " + msg);
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Netty实战之序列化与反序列化协议
    • 序列化与反序列化概念
      • 序列化的模式(两种)
        • 序列化图解
          • 什么rpc远程调用
            • 序列化的模式:
              • 序列化有哪几种方式?
                • MessagePack的使用案例:
                  • MessagePack和JSON序列的区别:
                    • 为什么要使用序列化
                      • 使用MessagePack进行对象实例
                        • 添加pom依赖
                        • 添加User实体类
                        • 创建自定义编码器MessagePackEncoder
                        • 创建自定义解码器MessagePackDecoder
                        • 创建自定义解码器NettyServer
                        • 创建ServerHandler
                        • 搭建NettyClient
                        • 创建ClientHandler
                    相关产品与服务
                    文件存储
                    文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档