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

这篇具有很好参考价值的文章主要介绍了【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 的路径可能不同。

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

  1. make

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

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

  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

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

  • 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()

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json


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 包:

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json
安装完后,可以查看需要的 pb.soprotoc.lua 两个文件的路径:

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

  • 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)

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json


使用 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 

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

由于我是通过 luaver 管理 luarockslua,使用 luarocks 分发 lua 模块,安装的 lua-protobuf。所以上述路径下,没有 pb.soprotoc.lua,直接找到安装路径下的,需要 luaver 使用 lualuarocks
【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

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

上述操作是在 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 文件。

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

.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 

【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf,Lua,rpc,lua,网络协议,protobuf,json

更多具体的 API 操作,参考官方 GitHub:https://github.com/starwing/lua-protobuf文章来源地址https://www.toymoban.com/news/detail-689134.html

到了这里,关于【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【序列化与反序列化】关于序列化与反序列化MessagePack的实践

    在进行序列化操作之前,我们还对系统进行压测,通过 jvisualvm 分析cpu,线程,垃圾回收情况等;运用火焰图 async-profiler 分析系统性能,找出程序中占用CPU资源时间最长的代码块。 代码放置GitHub:https://github.com/nateshao/leetcode/tree/main/source-code/src/main/java/com/nateshao/source/code/ser

    2024年02月11日
    浏览(57)
  • cJSON(C语言JSON)库(适用于嵌入式序列化和反序列化)

    JSON与序列化和反序列化 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,它以易于阅读和编写的文本形式表示结构化数据。JSON 格式广泛用于将数据从一个应用程序传输到另一个应用程序,特别是在Web应用程序中,因为它与JavaScript兼容,容易在客户端和服务器之间进

    2024年02月04日
    浏览(35)
  • 【Linux】序列化与反序列化

    目录 前言 什么是应用层? 再谈\\\"协议\\\"  什么是序列化和反序列化 网络版计算器 整体流程实现 Sock.hpp的实现 TcpServer.hpp的实现 Protocol.hpp的实现 CalServer.cc的编写 CalClient.cc的编写 整体代码           本章是属于TCP/UDP四层模型中的第一层 应用层 相关的内容。主要介绍了序列

    2024年02月10日
    浏览(40)
  • Flutter笔记:序列化与反序列化

    Flutter笔记 序列化与反序列化 作者 : 李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 : 291148484@163.com 本文地址 :https://blog.csdn.net/qq_28550263/article/details/133340592 序列化是一种将复杂数据结构(例如对象、数组、字典等)转换为线性格式或字节流的过程,以便于数据的存储

    2024年02月07日
    浏览(56)
  • 序列化与反序列化读取配置文件

    定义一个连接配置文件类OmCipNetParam 定义一个结构体,传递函数运行结果和运行信息 ​ 使用Newtonsoft.Json进行序列化和反序列化读写配置文件 同理反序列读取配置文件 注意这里需要引入库

    2024年02月08日
    浏览(57)
  • 4.4. 对象序列化与反序列化

    在本节中,我们将详细讨论Java中的对象序列化与反序列化概念、使用方法以及实例。对象序列化是将对象的状态信息转换为字节流的过程,而反序列化则相反,是将字节流恢复为对象的过程。 4.4.1 为什么需要对象序列化? 对象序列化的主要目的是为了在不同的系统间传输对

    2024年02月07日
    浏览(55)
  • 【计算机网络】序列化与反序列化

    通过打包的方式,将结构体message发送给对方 对方收到后就会报告给上层QQ客户端 结构化的数据 是由 多个 string 构成的 而以前在网络套接字 发送时,都是按照一个字符串的方式来发送和接收的 所以想办法 ,把多个字符串 转化为 一个大\\\"字符串\\\",对方在接收时也是一个长的

    2024年02月10日
    浏览(44)
  • Springboot Jackson 序列化与反序列化配置

    可解决在使用默认反序列化Jackson时,LocalDateTime类型的请求参数反序列化失败的问题

    2024年02月02日
    浏览(43)
  • 深入探究序列化与反序列化:原理、应用和最佳实践

    序列化 (Serialization)是指将对象转化为字节流的过程,以便于存储或通过网络进行传输。 反序列化 (Deserialization)则是将字节流转化为对象的过程,恢复原始对象的状态。 在计算机科学中,序列化和反序列化是常用的数据处理技术,用于在不同系统、不同编程语言之间传

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包