【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf

news2024/11/19 13:33:17

文章目录

    • RPC 协议
      • gRPC
      • JSON-RPC
    • 数据序列化与反序列化
      • lua-cjson
      • lua-protobuf

RPC 协议

在分布式计算,远程过程调用(英语:Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC 是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。

RPC 协议根据所使用的数据格式,可以分为有模式(schema)和无模式(schema-less)。

  • 有模式(schema)

通讯双方需要提前定义协议模板,在数据传输过程中只传输值,无需传输数据结构,节省流量。典型的有模式 RPC 协议是基于 Protobuf 接口描述语言来实现的,例如 gRPC。
优点是协议结构明确,解析效率高;缺点是不够灵活,协议变更需要重新定义。


  • 无模式(schema-less)

没有预定义数据结构,支持动态语言。无需协议模板,数据传输过程中需要带上数据结构。典型的无模式 RPC 协议是基于 JSON 来实现的, 例如 JSON-RPC 。
优点是协议灵活、易于扩展;缺点是解析效率较低。

通常我们会在数据序列化格式(如 Protobuf、JSON)的基础上,定制符合自己要求的 RPC 协议,灵活的在服务器和客户端之间通信。而不是采用通用的 RPC 框架,对于不需要的功能,增加了通信的开销。

gRPC

https://doc.oschina.net/grpc

JSON-RPC

https://wiki.geekdream.com/Specification/json-rpc_2.0.html


数据序列化与反序列化

lua-cjson

采用的 json for lua 库:https://github.com/cloudwu/lua-cjson

lua CJSON 网站: https://www.kyne.com.au/~mark/software/lua-cjson.php

安装步骤:

  1. git clone https://github.com/cloudwu/lua-cjson.git
  2. cd lua-cjson && sudo vim Makefile

修改如下:(版本 5.4,lua 文件前缀 /home/cauchy/.luaver/lua/5.4.6

由于我使用 luaver 来管理,所以这里 lua 的路径可能不同。

在这里插入图片描述

  1. make

执行完 Makefile,成功后会生成 cjson.so,我们只需要这个动态库。

在这里插入图片描述

  1. mv cjson.so ../ && cd .. && sudo rm -rf lua-cjson

这一步可不执行,只需要 cjson.sorequire "cjson" 时能找到即可,自己可以放置它的位置。


示例代码:

协议格式:

{
	"fid": "c2s_hello",
	"msg": "world"
}
{
	"fid": "s2c_hello",
	"succ": true, 
	"msg": "hello " .. "${msg}"
}

fid 用于映射 RPC 协议处理的函数名,fd 用于标识网络连接的文件描述符,JS_data 标识序列化后的 JSON 数据,data 是反序列化后的数据。


创建三个文件:libnet.luaserver.luaclient.lua

在这里插入图片描述

  • libnet.lua

模拟网络库,简易实现网络数据的收发过程。提供三个接口,发送消息给服务端,发送消息给客户端,连接服务器。

local M = {}

local server, client

function M.send_to_server(fd, JS_data)
    if not server then 
        server = require "server"
    end 
    server.dispatch(fd, JS_data)
end

function M.send_to_client(fd, JS_data)
    if not client then 
        client = require "client"
    end 
    client.dispatch(fd, JS_data)
end

local fd = 0
function M.connect_server()
    fd = fd + 1
    return fd
end 

return M 
  • server.lua

模拟服务器业务逻辑,实现处理客户端的请求。

local cjson = require "cjson"
local libnet = require "libnet"

local M = {}
local RPC = {}

function RPC.c2s_hello(data)
    return {
        fid = "s2c_hello",
        succ = true, 
        msg = "hello " .. data.msg
    }
end 

function M.dispatch(fd, JS_data)
    local data = cjson.decode(JS_data)
    local f = assert(RPC[data.fid], "Not exists Func: " .. data.fid)
    local ok, r = pcall(f, data)
    if ok then 
        libnet.send_to_client(fd, cjson.encode(r))
    end 
    return ok 
end 

return M
  • client.lua

模拟客户端业务逻辑,实现处理服务端的请求。

local cjson = require "cjson"
local libnet = require "libnet"

local M = {}
local RPC = {}

function RPC.s2c_hello(data)
    print(data.succ, data.msg)
end 

function M.dispatch(fd, JS_data)
    local data = cjson.decode(JS_data)
    local f = assert(RPC[data.fid], "Not exists Func: " .. data.fid)
    local ok, r = pcall(f, data)
    return ok 
end 

return M 

新建 main.lua,测试逻辑。

local cjson = require "cjson"
local libnet = require "libnet"

local function main()
    local fd = libnet.connect_server()

    local data = {
        fid = "c2s_hello",
        msg = "world"
    }
    local JS_data = cjson.encode(data)

    libnet.send_to_server(fd, JS_data)
end

main()

在这里插入图片描述


lua-protobuf

lua-protobuf 库:https://github.com/starwing/lua-protobuf

  1. luaver use 5.4.6
  2. luaver use-luarocks 3.9.2
  3. luarocks install lua-protobuf

使用 luarocks 来管理安装 lua 包:

在这里插入图片描述
安装完后,可以查看需要的 pb.soprotoc.lua 两个文件的路径:

在这里插入图片描述

  • pb.so:Protocol Buffers 的 Lua 语言动态库文件,通过在 Lua 中 require("pb") 来加载该库。

  • protoc.lua:Protocol Buffers 的 Lua 描述文件编译器,将 .proto 文件编译生成对应的 Lua 代码,生成的 Lua 代码依赖 pb.so 库来实现序列化和反序列化。

示例代码:

local pb = require "pb"
local protoc = require "protoc"

-- 直接载入schema (这么写只是方便, 生产环境推荐使用 protoc.new() 接口)
assert(protoc:load [[
   message Phone {
      optional string name        = 1;
      optional int64  phonenumber = 2;
   }
   message Person {
      optional string name     = 1;
      optional int32  age      = 2;
      optional string address  = 3;
      repeated Phone  contacts = 4;
   } ]])

-- lua 表数据
local data = {
   name = "ilse",
   age  = 18,
   contacts = {
      { name = "alice", phonenumber = 12312341234 },
      { name = "bob",   phonenumber = 45645674567 }
   }
}

-- 将Lua表编码为二进制数据
local bytes = assert(pb.encode("Person", data))
print(pb.tohex(bytes))

-- 再解码回Lua表
local data2 = assert(pb.decode("Person", bytes))
print(data2.name, data2.age, data2.contacts[1].name, data2.contacts[1].phonenumber, data2.contacts[2].name, data2.contacts[2].phonenumber)

在这里插入图片描述


使用 protoc.new() 创建一个编译器实例,加载 .proto 文件:

  • addressbook.proto
syntax = "proto3"; 

package cauchy; 

message Person {
    string name = 1; 
    int32 age = 2; 

    enum PhoneType {
        MOBILE = 0; 
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber {
        string number = 1;
        PhoneType type = 2; 
    }
    repeated PhoneNumber phones = 3;
}
  • main.lua
local protoc = require "protoc"
local pb = require "pb"

local data = {
   name = "cauchy",
   age  = 20,
   phones = {
      { number = "1234567890", type = 1 },
      { number = "0987654321" }
   }
}

local p = protoc.new()

local addressbook = io.open("addressbook.proto"):read("a")
p:load(addressbook)

local bytes = assert(pb.encode("cauchy.Person", data))
local data2 = assert(pb.decode("cauchy.Person", bytes))
print(data2.name, data2.age, data2.phones[1].number, data2.phones[1].type)

for name, id, types in pb.fields("cauchy.Person") do 
   print(name, id, types)
end 

在这里插入图片描述

由于我是通过 luaver 管理 luarockslua,使用 luarocks 分发 lua 模块,安装的 lua-protobuf。所以上述路径下,没有 pb.soprotoc.lua,直接找到安装路径下的,需要 luaver 使用 lualuarocks
在这里插入图片描述

不过使用者也可以直接拉取到执行脚本的路径下。

上述操作是在 lua 代码中,直接通过导入 protoc.lua 文件,来在运行时加载 .proto 文件的,无需提前编译,但是这样转换性能可能比较慢。


下面我们来安装 protoc 编译器:

  1. sudo apt update
  2. sudo apt install -y protobuf-compiler

protoc 默认安装在 /usr/bin/ 下。

执行 protoc -o addressbook.pb addressbook.proto 生成 .pb 文件。

在这里插入图片描述

.proto 文件:以 Protocol Buffers 语言编写的接口定义文件,用来定义数据结构、服务接口等。

.pb 文件:从 .proto 接口定义文件生成的目标语言代码文件,而没有指定目标语言,生成通用的二进制文件,包含了编码后的 Protocol Buffers 数据。

local pb = require "pb"

pb.loadfile("./addressbook.pb")

local data = {
   name = "cauchy",
   age  = 20,
   phones = {
      { number = "1234567890", type = 1 },
      { number = "0987654321"}
   }
}

local bytes = pb.encode("cauchy.Person", data)
print(pb.tohex(bytes))

local data2 = pb.decode("cauchy.Person", bytes)
print(data2.phones[2].number, data2.phones[2].type)

for name, id, types in pb.fields("cauchy.Person") do 
   print(name, id, types)
end 

在这里插入图片描述

更多具体的 API 操作,参考官方 GitHub:https://github.com/starwing/lua-protobuf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/962073.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity Android 之 在Unity 中引入 OkHttp的操作注意(OKHttp4.xx- kotlin 的包)简单记录

Unity Android 之 在Unity 中引入 OkHttp的操作注意(OKHttp4.xx- kotlin 的包)简单记录 目录 Unity Android 之 在Unity 中引入 OkHttp的操作注意(OKHttp4.xx- kotlin 的包)简单记录 一、简单介绍 二、OKHttp 4.xx 的 SDK 封装 aar 给 Unity 的使用注意 三、附录 OKHttp 的…

一米ip流量池系统

PC端快速切换移动网络IP 支持全网通sim卡槽,国内三大运营商IP池动态切换,实现真实移动端IP切换。从此换IP再也不用vpn或代理,一个设备搞定 1.兼容国内电信,移动,联通三网通的sim卡4G连接,快速稳定2.可直接…

《算法竞赛·快冲300题》每日一题:“简化农场”

《算法竞赛快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 简…

SpringBoot自定义消息总线

一、前言 在现代的分布式系统中,消息传递已成为一个非常流行的模式。它使得系统内的不同部分可以松耦合地通信,从而实现更高效、更可靠的应用程序。本博客将介绍SpringBoot如何提供简单易用的消息传递机制,并展示如何自定义消息总线以满足特定…

安装使用 d3graph 时出现 TypeError 的解决方法

使用 python 3.7 pip 22.3.1 在清华镜像源 https://pypi.tuna.tsinghua.edu.cn/simple 安装 d3blocks 1.3.2 时,安装成功后导入包时出错: 观察报错信息可以看到出错的代码(902 行)使用了类型指定语法,这是最新的 pyth…

stable diffusion实践操作-电脑硬件查看

本文专门开一节写电脑硬件相关的内容,在看之前,可以同步关注: stable diffusion实践操作 正文 1、检查电脑显存的方法(win10): 鼠标放在工具栏,单击右键打开“任务管理器”,选择顶…

jmeter 固定定时器

固定定时器(Constant Timer)是一个定时器元件,可以在线程组中的每个线程之间添加固定的延迟时间。固定定时器会对每个线程的执行进行一定的暂停。 聊一下和线程组中的调度器对线程组执行时长的影响: 相同: 都会影响线…

【线性代数】矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇)

矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇) 说在前面一. 函数与标量、向量、矩阵二. 矩阵求导的本质三. 矩阵求导结果的布局四. 分子布局、分母布局的本质五. 向量变元的实值标量函数 说在前面 我将严谨地说明矩阵求导的本质与分子布…

游戏思考30(补充版):关于逆水寒铁牢关副本、白石副本和技能的一些注释(2023/0902)

前期介绍 我是一名逆水寒的玩家,做一些游戏的笔记当作攻略记录下来,荣光不朽-帝霸来源视频连接 传送门 一、旧版铁牢关(非逆水寒老兵服) (1)老一:巨鹰 1)机制一:三阵风…

多通道振弦数据记录仪应用桥梁安全监测的关键要点

多通道振弦数据记录仪应用桥梁安全监测的关键要点 随着近年来桥梁建设和维护的不断推进,桥梁安全监测越来越成为公共关注的焦点。多通道振弦数据记录仪因其高效、准确的数据采集和处理能力,已经成为桥梁安全监测中不可或缺的设备。本文将从以下几个方面…

JavaScript基础02

JavaScript 基础 文章目录 JavaScript 基础运算符算术运算符赋值运算符自增/自减运算符比较运算符逻辑运算符运算符优先级 语句表达式和语句分支语句if 分支语句if双分支语句if 多分支语句三元运算符(三元表达式)switch语句(了解)…

孙哥Spring源码第16集

第16集 refresh()-prepareBeanFactory分析 【视频来源于:B站up主孙帅suns Spring源码视频】 1、设置类加载器 2、设置SpringEL表达式 解析器 3、设置内置的属性编辑器 (类型转换器) 3.1、如何实现类型转化? 1、Converter 2、P…

Ubuntu 20.04 Server配置网络

0,环境 服务器: Intel(R) Xeon(R) Gold 6248R CPU 3.00GHz 96核 网卡: 多网卡 1, 镜像下载 http://old-releases.ubuntu.com/releases/ubuntu-20.04.1-desktop-amd64.iso 2, 系统安装--具体步骤就不贴出来&#…

Navicat 强大的数据模型功能 | 面向数据库设计、架构和数据资产梳理等使用场景

数据模型是用来描述数据、组织数据和对数据进行操作的一组概念和定义。根据不同的应用需求,数据模型可以分为概念模型、逻辑模型和物理模型。这些数据模型帮助数据库设计人员设计和管理数据库,以满足用户的需求。 Navicat 强大的数据模型功能主要适用于…

Linux c++开发-03-使用CMake组织工程

一、简单文件的编译 有如下的目录结构&#xff1a; 其中 helloworld.cpp如下&#xff1a; #include <iostream> using namespace std; int main() {printf("hello world my name is Ty!");return 0; }CMakeLists.txt如下&#xff1a; cmake_minimum_requir…

cocos creator配置终端调试

在launch.json里添加"preLaunchTask":“CocosCreator compile” 在cocos creator里选择开发者&#xff0c;visual studio code工作流&#xff0c;选择添加编译任务。 添加 settings.json {"files.exclude":{"**/.git": true,"**/.DS_Sto…

数据结构与算法(三)线性表

线性表定义 线性表&#xff08;List&#xff09;&#xff1a;零个或多个数据元素的有限序列。 首先它是一个序列&#xff0c;其次&#xff0c;线性表强调是有限的。 前驱元素&#xff1a;若A元素在B元素的前面&#xff0c;则称A为B的前驱元素 后继元素&#xff1a;若B元素在…

【代码随想录day23】不同路径

题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff1f; 示…

明茨伯格的人际关系角色理论

明茨伯格的人际关系角色理论是由社会心理学家明茨伯格&#xff08;William Schutz&#xff09;在20世纪50年代提出的一种关于人际关系的理论。该理论主要探讨了人际关系中的三个角色&#xff1a;包容性、控制性和亲密性。这些角色代表了人们在互动中所表现出的行为和需求。下面…

ClickHouse进阶(六):副本与分片-2-Distributed引擎

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术,IT贫道_Apache Doris,大数据OLAP体系技术栈,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅…