SimpleRpc-序列化与反序列化的设计与实现
为什么需要序列化和反序列化?
假设你是客户端,现在要调用远程的加法计算服务,你与服务端商定好了发送数据的格式:发送8个字节的请求,前4字节是第一个数,后4字节是第二个数,服务端读取数据的时候也按照商定的方式读取。其实,这就是一个序列化和反序列化的过程。序列化:2个数字变成8个字节数据,反序列化:8个字节数据变成2个数字。但是这么做有个问题,那就是太容易出错,每次你还得考虑按照什么形式排列字段,每个字段几个字节,还要考虑大端小端等。
为了解决这个重复性并且容易出错的过程,我们有一个小小的改进:把常用数据类型的序列化和反序列化代码封装成基础库:
int readInt(char *, int size) //读一个整数
int writeInt(int, char *, int size) //写一个整数
double readDouble(char *, int size) //读一个double型数
int writeDouble(double, char *, int size) //写一个double型数
float readFloat(char *, int size) //读一个浮点数
int writeFloat(float, char *, int size) //写一个浮点数
string readString(char *, int size) //读一个字符串
int writeString(string, char *, int size) //写一个字符串
现在,我们可以序列化任何基础类型数据。但是有个问题来了:怎么序列化结构体咧?仔细想一下,结构体也是由最基本的数据类型组成的啊,我们可能会有下面的方案:
class SimpleRequest {
int a;
int b; int serialize(char *buf, int size) {
writeInt(a, buf, size);
writeInt(b, buf + , size - );
return ;
} int deserialize(char *buf, int size) {
a = readInt(buf, size);
b = readInt(buf + , size - );
return ;
}
};
但有些结构体中套用结构体,这种情况怎么处理呢?很好办,因为只要是结构体我们就已经实现了serialize和deserialize接口,只要调用这两个函数就可以。所以,最终的方案就是:对于基础数据类型,通过readXX和writeXX序列化,结构体类型通过serialize/deserialize序列化。
由于基础数据类型数目有限可枚举,并且结构体定义也有一定的语法,我们完全可以设计一个语法解析器,读取IDL定义的文件,自动生成序列化和反序列化的代码。大致流程如下:使用BNF范式来编写规则,用来描述我们自己定义的IDL(接口描述语言);然后使用JAVACC或者YACC根据编写的BNF范式生成解析IDL语言的代码,利用生成的代码解析我们用IDL定义的结构体文件,根据语法树查找其中的基础数据类型、用户自定义结构体,并进行有针对性的进行解析。Thrift和grpc的IDL解析都是这么做的,有兴趣的同学可以自己玩一下Javacc和yacc。
SimpleRpc的序列化与反序列化设计方案
SimpleRpc没有自己的序列化和反序列化具体实现方案,它要求用户自己实现这部分代码。我们的例子中使用的protobuf,protobuf在SimpleRpc并不是必须的,你可以换成任何一种序列化方式。SimpleRpc的设计方案如下图所示:
Request和Response是请求和响应的基类,继承自Serializable接口,必须实现三个函数:
- serialize函数,把request/response序列化到参数指定的数组中。
- deserialize函数,把参数指定的数组中的二进制字节流反序列化成request/response。
- bytes函数,得到结构体序列化成字节流的大小。
AddRequest和AddResponse是用户端必须实现的代码,我的例子中在这两个类里面嵌套了protobuf定义的request和response,当框架根据多态调用序列化和反序列化函数时,相应的类通过调用其成员protobuf实例的序列化和反序列化代码。由于框架所看到的结构都是Request或者是Response,隐藏其中的protobuf对框架而言是不可见的,你可以更换成任意一种序列化和反序列化方式。
小伙伴们可能有疑问,为什么AddRequest和AddResponse不直接继承自Serialzable,而是继承自中间的那层Request和Response,是不是多余了?是因为,Request和Response除了实现序列化和反序列化之外,还有其它接口需要实现,这里面为了只突出序列化相关而忽略了其它接口。
与其它RPC的设计方案对比
最早接触到的序列化是在Java的远程调用RMI中,但是Java的序列化太笨拙,它不仅序列化数据成员,还序列化其对象间引用关系,这导致其序列化后的字节数非常多,不是一种高效率的手段。接下来遇到的就是ICE以及Thrift中序列化,但是其序列化模块是和整个框架绑定到一起,为了只用一个序列化功能,你必须安装整个框架,还是有些笨拙。直到遇到了protobuf,它真正的把序列化从RPC框架中抽离出来,成为了现在使用最多的序列化框架。
我们的RPC和其它的RPC的不同点就在于,序列化和框架是分离的,你可以自由更换序列化方式,只要你实现了Request和Response接口(你甚至都可以自己针对特定的请求响应硬编码字节流),给用户更多的选择性。
SimpleRpc-序列化与反序列化的设计与实现的更多相关文章
- 高性能的序列化与反序列化:kryo的简单使用
前言:kryo是个高效的java序列化/反序列化库,目前Twitter.yahoo.Apache.strom等等在使用该技术,比如Apache的spark.hive等大数据领域用的较多. 为什么使用k ...
- DRF框架(三)——media资源路径设置、多表设计复习及补充、序列化组件(ModelSerializer)操作多表(序列化与反序列化)、多表序列化与反序列化整合(重点)
media资源路径设置 (设置好后把图片放在这个文件夹中,通过链接能访问到图片) 1.先在根目录设置一个media文件夹 2.配置settings.py,加上下面的 MEDIA_URL = '/me ...
- C#对象序列化与反序列化zz
C#对象序列化与反序列化(转载自:http://www.cnblogs.com/LiZhiW/p/3622365.html) 1. 对象序列化的介绍........................ ...
- C#对象序列化与反序列化
C#对象序列化与反序列化(转载自:http://www.cnblogs.com/LiZhiW/p/3622365.html) 1. 对象序列化的介绍.......................... ...
- Asp.net中Json的序列化和反序列化(一)
JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...
- 序列化和反序列化的几种方式(JavaScriptSerializer 、XmlSerializer、DataContractSerializer)(一)
JavaScriptSerializer 类 为启用 AJAX 的应用程序提供序列化和反序列化功能. 命名空间: System.Web.Script.Serialization 程序集: Sys ...
- ASP.NET中JSON的序列化和反序列化
JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍 ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介 ...
- java中对象的序列化和反序列化
[对象的序列化和反序列化 ] 1.定义:序列化--将对象写到一个输出流中.反序列化则是从一个输入流中读取一个对象.类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能 ...
- lintcode : 二叉树的序列化和反序列化
题目 二叉树的序列化和反序列化 设计一个算法,并编写代码来序列化和反序列化二叉树.将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”. 如何反序列化或序列化二叉树是没有限制 ...
随机推荐
- android studio多渠道多包名多apk打包
转自 利用 Android Studio 和 Gradle 打包多版本APK 搬砖的道路上,经常会有各种不同的需求,比如今天就碰到过一个打包版本的apk的要求, 比如一个apk给多个客户使用,如张三 ...
- SQL注入-攻入Apple ID钓鱼网站实录
之前写的一篇利用SQL注入方式攻击钓鱼网站的文章,现在在博客园再分享一下. 下午,朋友发了一条朋友圈,内容大概这样: 大体就是她的iPhone丢了,收到了钓鱼短信,多么熟悉的套路,如下: 还好她比较机 ...
- elasticsearch报错expected <block end>, but found BlockMappingStart解决方法
我用的是elasticsearch2.4.0,在修改完配置文件就出现类似格式 expected <block end>, but found BlockMappingStart...... ...
- 四种JavaScript隐式类型转换的总结
一般存在四种情况,JavaScript会对变量的数据类型进行转换. 目录 * if中的条件会被自动转为Boolean类型 * 会被转为false的数据 * 会被转为true的数据 * 参与+运算都会被 ...
- Openfire分析之一:Openfire与XMPP协议
引言 上帝说,要有光,于是就有了光. 有点玄. 如果将时光回溯无数岁月,到几百万年的蛮荒时代,人类史上第一次发生信息交换,会是什么样子?是转一下脑袋,还是眨一下眼? 但不管是什么形式,于是有了信息, ...
- linux(十)之初始化文件
前面写了很多linux的知识,其实很多都是命令的,所以要去多多的练习才能学的更好,加油为了好工作. 要么现在懒惰,未来讨饭.要么现在努力,未来惬意. 一.初始化文件概述 1.1.概述 系统初始化文件是 ...
- spring MVC处理请求过程及配置详解
本文主要梳理下Spring MVC处理http请求的过程,以及配置servlet及业务application需要的常用标签,及其包含的意义. spring MVC处理请求过程 首先看一个整体图 简单说 ...
- MongoDB基本shell操作
---------------------MongoDB基本操作--------------------- 1.MongoDB创建数据库 use 数据库名:切换到指定的数据库中,在插入第一个条 ...
- 【小白成长撸】--顺序栈(C语言版)
// 顺序栈.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h"//test1.0--栈表仅限Int类型 #include <stdio. ...
- IOS学习[Swift中跳转与传值]
Swift中页面跳转与传值: 1.简单方式 首先,Swift的跳转可分为利用xib文件跳转与storyboard跳转两种方法,我这里选择使用storyboard的界面跳转方法. 1.通过在storyb ...