IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【自己动手实现一个简单的RPC框架】4、[v2.0]利用Netty传输数据;利用Kryo实现序列化 -> 正文阅读

[网络协议]【自己动手实现一个简单的RPC框架】4、[v2.0]利用Netty传输数据;利用Kryo实现序列化

本文学习的代码地址:https://github.com/Snailclimb/guide-rpc-framework
本文代码地址:https://gitee.com/uamaa/msc-rpc-framework

【前言】本文主要实现了如下改进:
1.利用Netty传输数据
2.利用Kyro实现序列化

0 查看代码有哪些改动

新创建了例子客户端与服务器,跟之前的大差不差,
旧例子的RpcClient和RpcServer变成SocketRpcClient和SocketRpcServer,
新例子用的NettyRpcClient和NettyRpcServer

在这里插入图片描述
这里变了一点,我觉得这样更合理,代理和地址没得关系的
在这里插入图片描述
加了一个序列化异常类
在这里插入图片描述
加了序列化模块
在这里插入图片描述
加了Netty传输模块

1 看懂代码

本次版本改进就是引入了Kryo和Netty,Kryo服务于Netty,所以我们先看Kryo模块,再看Netty模块。

1.1 Kryo

在这里插入图片描述
先定义了一个序列化接口,声明序列化与反序列化方法
然后KryoSerializer实现该接口类
这么做的好处是:接口只负责提出需求,具体的实现需要具体的实现类来做,可能这一版用的是Kryo来实现。下一版又引入了新的技术,只需要新建新技术的实现类就行了,方便程序扩展

官方文档: https://github.com/EsotericSoftware/kryo
文档里提供了快速入门的简单例子

public class TestKryo {
    static public void main (String[] args) throws Exception {
        Kryo kryo = new Kryo();
        kryo.register(SomeClass.class);

        SomeClass object = new SomeClass();
        object.value = "Hello Kryo!";

        Output output = new Output(new FileOutputStream("D:\\file.txt"));
        kryo.writeObject(output, object);//序列化
        output.close();

        Input input = new Input(new FileInputStream("D:\\file.txt"));
        SomeClass object2 = kryo.readObject(input, SomeClass.class);//反序列化
        input.close();

        System.out.println(object2.value);
    }
    static public class SomeClass {
        String value;
    }

}

在这里插入图片描述
在这里插入图片描述
Output 类是一个将数据写入字节数组缓冲区的 OutputStream
Input 类是一个从字节数组缓冲区读取数据的 InputStream

例子说的很清楚流程:
1.自定义类在Kryo种注册
2.声明输出流Output,并将数据序列化成字节数组(writeObject)写入输出流 - 实现序列化
3.声明输入流Input,将输入流的字节数组反序列化成指定类(readObject) - 实现反序列化

由于 Kryo 不是线程安全的。每个线程都应该有自己的 Kryo,Input 和 Output 实例。所以,使用 ThreadLocal 存放 Kryo 对象

为什么要用Kryo而不用Serializable?
1.Kryo序列化的性能更高(来源:Java原生序列化和Kryo序列化性能比较
2.Kryo序列化后的体积更小(来源:jackson、fastjson、kryo、protostuff等序列化工具性能对比
3.Kryo提供了简单易用的API

1.2 Netty

在这里插入图片描述
这个结构很简单,Netty网络传输所必须的:客户端、服务端、客户端业务处理Handler、服务端业务处理Handler、编码器、解码器

NettyRpcServer跟https://zhuanlan.zhihu.com/p/181239748这篇文章的差不多,
workerGroup的EventLoop对应的管道设置 这里有所不同
本项目用的是:解码、编码、服务端业务处理Handler
NettyRpcServer和NettyRpcClient跟套公式一样
主要是客户端业务处理Handler、服务端业务处理Handler的逻辑。

1.2.1 NettyClientHandler

继承ChannelInboundHandlerAdapter
在这里插入图片描述
因为channelRead没有返回值,要把RpcResponse传给NettyClient就需要声明一个AttributeKey对象。Channel上的AttributeMap就是大家共享的,每一个ChannelHandler都能获取到
在这里插入图片描述

1.2.2 NettyServerHandler

继承ChannelInboundHandlerAdapter

将发来的数据转成RpcRequest类,从中取到接口名,从注册中心中取到服务,转给RpcRequestHandler处理得到返回数据,将返回数据发送给客户端(ctx.writeAndFlush)

1.2.3 NettyKryoEncoder

编解码器参考资料:《Netty4核心原理》谭勇德

用户自定义编码器继承MessageToByteEncoder,只需要实现void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) 抽象方法即可完成ByteBuf到Java对象的编码。

编码器可以将写出的数据进行拦截处理。在本项目中就是在数据写入ByteBuf对象之前,先写入数据对应的长度

这里原作者Guide的注释写得很清楚了

    /**
     * 将对象转换为字节码然后写入到 ByteBuf 对象中
     */
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) {
        if (genericClass.isInstance(o)) {
            // 1. 将对象转换为byte
            byte[] body = serializer.serialize(o);
            // 2. 读取消息的长度
            int dataLength = body.length;
            // 3.写入消息对应的字节数组长度,writerIndex 加 4
            byteBuf.writeInt(dataLength);
            //4.将字节数组写入 ByteBuf 对象中
            byteBuf.writeBytes(body);
        }
    }

1.2.4 NettyKryoDecoder

用户自定义解码器继承ByteToMessageDecoder,只需要实现void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List< Object> list) 抽象方法即可完成ByteBuf到Java对象的解码。

由于ByteToMessageDecoder并没有考虑TCP粘包和拆包等场景,用户自定义解码器需要自己处理“读半包”问题。

所以要先处理“读半包”问题,再序列化(序列化就是借助Kryo序列化)

同样原作者Guide的注释写得很清楚

	/**
     * Netty传输的消息长度也就是对象序列化后对应的字节数组的大小,存储在 ByteBuf 头部
     */
    private static final int BODY_LENGTH = 4;

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) {

        //1.byteBuf中写入的消息长度所占的字节数已经是4了,所以 byteBuf 的可读字节必须大于 4,
        if (byteBuf.readableBytes() >= BODY_LENGTH) {
            //2.标记当前readIndex的位置,以便后面重置readIndex 的时候使用
            byteBuf.markReaderIndex();
            //3.读取消息的长度
            //注意: 消息长度是encode的时候我们自己写入的,参见 NettyKryoEncoder 的encode方法
            int dataLength = byteBuf.readInt();
            //4.遇到不合理的情况直接 return
            if (dataLength < 0 || byteBuf.readableBytes() < 0) {
                return;
            }
            //5.如果可读字节数小于消息长度的话,说明是不完整的消息,重置readIndex
            if (byteBuf.readableBytes() < dataLength) {
                byteBuf.resetReaderIndex();
                return;
            }
            // 6.走到这里说明没什么问题了,可以序列化了
            byte[] body = new byte[dataLength];
            byteBuf.readBytes(body);
            // 将bytes数组转换为我们需要的对象
            Object obj = serializer.deserialize(body, genericClass);
            list.add(obj);
        }
    }

2 自己动手

因为SocketRpcClient和NettyRpcClient都要用到RpcClientProxy,传入对应实例,所以整一个接口RpcClient,让SocketRpcClient和NettyRpcClient实现接口RpcClient,就能够统一写法

把类都建好之后,先从NettyRpcClient开始,实现RpcClient接口

为什么我的输出台多了很多DEBUG日志?
好了,修改了依赖,现在日志变成红色了。。。

3 总结

学到的知识:
1.由于 Kryo 不是线程安全的,所以,使用 ThreadLocal 存放 Kryo 对象
2.将接口类与实现类分离方便程序扩展
3.不懂的技术就看官网文档,有快速入门的简单例子(例:Kryo);或者看书,比较全面(例:Netty)
4.NettyClient怎么从NettyClientHandler中得到RpcResponse对象?通过AttributeKey
5.为什么要用Kryo而不是Serializabler?因为Kryo序列化的性能更高,序列化之后的体积更小,提供简易的API

本次改进:
1.利用Netty传输数据
2.利用Kryo实现序列化

疑问:
1.为什么要把这一坨放在static里?
在这里插入图片描述

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 16:25:55  更:2022-04-06 16:26:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:50:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码