skynet 使用protobuf
一、安装protobuf
下面的操作方法都是在 centos 环境下操作
#下载 Protocol Buffers 源代码:
#您可以从 Protocol Buffers 的 GitHub 仓库中获取特定版本的源代码。使用以下命令克隆仓库
git clone -b v3.20.3 https://github.com/protocolbuffers/protobuf.git#编译和安装:
#进入克隆的目录,然后编译和安装 Protocol Buffers:
cd protobuf
./autogen.sh
./configure
make
sudo make install#验证安装:
protoc --version#您应该看到输出,指示安装的版本为 3.20.3。
二、安装pdb库
#第三方库安装在3rd目录下
cd skynet/3rd/
git clone https://github.com/cloudwu/pbc.gitcd pbc
make#编译成功后,打开skynet/3rd/pbc/binding/lua53/Makefile文件,修改里面的lua路径
CC = gccCFLAGS = -O2 -fPIC -WallLUADIR = ../../../lua #这个路劲就是skynet/3rd/luaTARGET = protobuf.so.PHONY : all cleanall : $(TARGET)$(TARGET) : pbc-lua53.c$(CC) $(CFLAGS) -shared -o $@ -I../.. -I$(LUADIR) -L../../build $^ -lpbcclean :rm -f $(TARGET)#去到lua53目录,编译生成protobuf.so库
cd ./binding/lua53
sudo make
三、将依赖文件放到工程目录下
将 protobuf.so 和 protobuf.lua 分别放入 luaclib 、lualib
cp protobuf.so ../../../../luaclib/ #将protobuf.so复制到存放C模块的lualib目录中
cp protobuf.lua ../../../../lualib/ #将protobuf.lua复制到存放Lua模块的lualib目录中
四、创建protobuf目录
在skynet目录下创建protobuf目录,用来存放原始 .proto 描述文件
这里举例 login.proto
mkdir protobuflogin.proto的内容如下代码所示:
syntax = "proto3";
package Login;message login {string account=1;string passwd=2;int32 result=3;
}
五、编译proto文件
protoc --descriptor_set_out login.pb login.proto
这里写了个gen_pb.sh脚本,将protobuf目录下的所有.sproto文件转成proto文件
#!/bin/bash # 指定要遍历的目录,这里使用当前目录"."
dir="." # 使用find命令查找所有.proto文件,并调用basename和cut命令来截取文件名
find "$dir" -type f -name "*.proto" | while read -r filepath; do # 使用basename命令获取文件名部分,然后使用cut命令去除后缀 filename=$(basename "$filepath") filename_without_extension="${filename%.*}" # 输出截取后的文件名 echo "$filename, $filename_without_extension" # 在这里可以添加其他操作,比如使用protoc编译等 protoc --descriptor_set_out "$filename_without_extension.pb" "$filename"
done
六、了解protobuf.lua 关键函数
1、 protobuf.register
- 功能:注册 Protobuf
- 参数:buffer .pb文件读取出来的二进制字符串
- 返回值:无。
function M.register(buffer)c._env_register(P, buffer)
end
备注: register需要自己去加载.pb文件内容,下面的register_file函数使用会更多
2、protobuf.register_file
- 功能:注册 Protobuf
- 参数:filename 为 .pb文件名。
- 返回值:无。
function M.register_file(filename)local f = assert(io.open(filename , "rb"))local buffer = f:read "*a"c._env_register(P, buffer)f:close()
end
3、protobof.encode
- 功能:将一个 Lua 表编码为 Protobuf 格式的二进制消息。
- 参数:
message
是注册的 Protobuf 定义的名称,msg
是要编码的 Lua 表。 - 返回值:编码后的二进制数据。
function M.encode( message, t , func , ...)local encoder = c._wmessage_new(P, message)assert(encoder , message)encode_message(encoder, message, t)if func thenlocal buffer, len = c._wmessage_buffer(encoder)local ret = func(buffer, len, ...)c._wmessage_delete(encoder)return retelse local s = c._wmessage_buffer_string(encoder)c._wmessage_delete(encoder)return send
end
4、protobof.decode
- 功能:将一个 Protobuf 编码的二进制消息解码为 Lua 表。
- 参数:
typename
是注册的 Protobuf 定义的名称,buf
是包含 Protobuf 编码消息的二进制数据。 - 返回值:解码后的 Lua 表。
function M.decode(typename, buffer, length)local ret = {}local ok = c._decode(P, decode_message_cb , ret , typename, buffer, length)if ok thenreturn setmetatable(ret , default_table(typename))elsereturn false , c._last_error(P)end
end
七、protobuf测试用例
在examples 目录下新建 test_protobuf.lua
package.path = package.path .. ";./lualib/?.lua"
package.cpath = package.cpath .. ";./luaclib/?.so"local protobuf = require "protobuf" --引入文件protobuf.lua
protobuf.register_file "./protobuf/common.pb" --注册pb文件
protobuf.register_file "./protobuf/login.pb" --注册pb文件local loginInfo = { account = "test", passwd = "pw"} local encodeData = protobuf.encode("Login.login", loginInfo)
print("encodeData:", encodeData)local decodeData = protobuf.decode("Login.login", encodeData)
print("decodeData account:", decodeData.account)
print("decodeData passwd:", decodeData.passwd)
八、skynet 使用protobuf进行网络通信
1、 将数据打包成二进制数据
--[[big endianhead 2 byte body size2 byte protonamesizen byte protonamebody n byte data@desc: 将lua格式的协议序列化为二进制数据
]]
function protobufDataHelper.encode( name,data )local stringbuffer = protobuf.encode(name, data) -- protobuf序列化 返回lua stringlocal body = string.pack(">s2s",name,stringbuffer) -- 打包包体 协议名 + 协议数据local head = string.pack(">I2",#body) -- 打包包体长度print("encode proto_name:", name, ",data_size:", #body, ",totalSize:", #head+#body)return head .. body -- 包体长度 + 协议名 + 协议数据
end
2、将二进制数据解包
--[[@desc: 将二进制数据反序列化为lua string--@msg: C Point @return:协议名字,协议数据
]]
function protobufDataHelper.decode( msg )--- 前两个字节在netpack.filter 已经解析print("msg size:", #msg)local proto_name,stringbuffer = string.unpack(">s2s",msg)print("proto_name", proto_name, "data:", stringbuffer)local body = protobuf.decode(proto_name, stringbuffer)return proto_name,body
end
3、skyent unpack类型指定为二进制字符串
这里在agent.lua 注册消息协议类型时处理
skynet.register_protocol {name = "client",id = skynet.PTYPE_CLIENT, unpack = skynet.tostring, --- 将C point 转换为lua 二进制字符串
}
在dispatch_message消息地方反序列化消息
--- 分发消息
local function dispatch_message(msg)--- 反序列化二进制string数据local pack_name,data = dataHelper.decode(msg) -- pack_name = c2s.testlocal sub_name = pack_name:match(".+%.(%w+)$") -- sub_name = test......local f = REQUEST[sub_name]if f == nil thenprint("not function define handle package:", pack_name)returnendf(data)
end
agent.lua 改造测试代码如下
local skynet = require "skynet"
local socket = require "skynet.socket"
local sproto = require "sproto"
local sprotoloader = require "sprotoloader"
local login = require "login"
local tableutil = require "tableutil"local dataHelper = require "protobufDataHelper"local WATCHDOG
local host
local send_requestlocal CMD = {}
local REQUEST = {}
local client_fdfunction REQUEST:get()print("get", self.what)local r = skynet.call("SIMPLEDB", "lua", "get", self.what)return { result = r }
endfunction REQUEST:set()print("set", self.what, self.value)local r = skynet.call("SIMPLEDB", "lua", "set", self.what, self.value)
endfunction REQUEST:handshake()return { msg = "Welcome to skynet, I will send heartbeat every 5 sec." }
endfunction REQUEST:quit()skynet.call(WATCHDOG, "lua", "close", client_fd)
endlocal function send_data(name, args)local data = dataHelper.encode(name, args)-- 发送数据socket.write(client_fd,data)
endfunction REQUEST:login()print("login account,passwd:", self.account, self.passwd)local result = login.loginRequest(self.account, self.passwd)if result ~= 0 thenprint("kill client, client_fd:", client_fd)REQUEST:quit()endlocal loginInfo = { account = "kk", passwd = "haha"}send_data("Login.login", loginInfo)return {result = result}
endfunction REQUEST:loginTest()print("loginTest:", tableutil.tPrint(self))
endlocal function request(name, args, response)local f = assert(REQUEST[name])print("recieve request, protoName:", name, tableutil.tPrint(args))local r = f(args)if response thenreturn response(r)end
endlocal function send_package(pack)local package = string.pack(">s2", pack)socket.write(client_fd, package)
end--[[
skynet.register_protocol {name = "client",id = skynet.PTYPE_CLIENT,unpack = function (msg, sz)return host:dispatch(msg, sz)end,dispatch = function (fd, _, type, ...)assert(fd == client_fd) -- You can use fd to reply messageskynet.ignoreret() -- session is fd, don't call skynet.retskynet.trace()if type == "REQUEST" thenlocal ok, result = pcall(request, ...)if ok thenif result thensend_package(result)endelseskynet.error(result)endelseassert(type == "RESPONSE")error "This example doesn't support request client"endend
}--]]skynet.register_protocol {name = "client",id = skynet.PTYPE_CLIENT, unpack = skynet.tostring, --- 将C point 转换为lua 二进制字符串
}function CMD.start(conf)local fd = conf.clientlocal gate = conf.gateWATCHDOG = conf.watchdog-- slot 1,2 set at main.luahost = sprotoloader.load(1):host "package"send_request = host:attach(sprotoloader.load(2))skynet.fork(function()local index = 1while true do--send_package(send_request "heartbeat")index = index + 1local loginInfo = { account = "kk"..index, passwd = "haha"}send_data("Login.login", loginInfo)skynet.sleep(500)endend)client_fd = fdskynet.call(gate, "lua", "forward", fd)
endfunction CMD.disconnect()-- todo: do something before exitskynet.exit()
end--- 分发消息
local function dispatch_message(msg)--- 反序列化二进制string数据local pack_name,data = dataHelper.decode(msg) -- pack_name = c2s.testlocal sub_name = pack_name:match(".+%.(%w+)$") -- sub_name = testprint("recieve request, protoName:", pack_name, tableutil.tPrint(data))local f = REQUEST[sub_name]if f == nil thenprint("not function define handle package:", pack_name)returnendf(data)
endskynet.start(function()skynet.dispatch("lua", function(_,_, command, ...)skynet.trace()local f = CMD[command]skynet.ret(skynet.pack(f(...)))end)skynet.dispatch("client", function (session, address, msg)dispatch_message(msg)end)
end)
4、客户端测试代码
client_protobuf.lua
package.cpath = "luaclib/?.so;skynet/luaclib/?.so"
package.path = "lualib/common/?.lua;lualib/?.lua;skynet/lualib/?.lua;skynet/examples/?.lua"local tableutil = require "tableutil"if _VERSION ~= "Lua 5.4" thenerror "Use lua 5.4"
endlocal socket = require "client.socket"
local dataHelper = require "protobufDataHelper"local fd = assert(socket.connect("127.0.0.1", 8888))local function send_data(name, args)local data = dataHelper.encode(name, args)-- 发送数据socket.send(fd,data)
endlocal loginInfo = { account = "test", passwd = "haha"}
send_data("Login.login", loginInfo)
send_data("Common.heartbeat", {})local function unpack_package(text)local size = #textif size < 2 thenreturn nil, textendlocal s = text:byte(1) * 256 + text:byte(2)if size < s+2 thenreturn nil, textendreturn text:sub(3,2+s), text:sub(3+s)
endlocal function recv_package(last)local resultresult, last = unpack_package(last)if result thenreturn result, lastendlocal r = socket.recv(fd)if not r thenreturn nil, lastendif r == "" thenerror "Server closed"endreturn unpack_package(last .. r)
endlocal last = ""
local function dispatch_package()while true dolocal vv, last = recv_package(last)if not v thenbreakendlocal packName, data = dataHelper.decode(v)print("packName:", packName)print("data:", tableutil.tPrint(data) )end
endwhile true dodispatch_package()socket.usleep(1000000)
end
相关文章:
skynet 使用protobuf
一、安装protobuf 下面的操作方法都是在 centos 环境下操作 #下载 Protocol Buffers 源代码: #您可以从 Protocol Buffers 的 GitHub 仓库中获取特定版本的源代码。使用以下命令克隆仓库 git clone -b v3.20.3 https://github.com/protocolbuffers/protobuf.git#编译…...
Vue Router 4 与 Router 3 路由配置与区别
文章目录 路由安装路由配置vue-router 3.x版本写法配置路由使用路由 vue-router 4.x版本写法配置路由使用路由 Vue Router 4 与 Vue Router 3 区别 路由安装 Vue 2 (使用 Vue Router 3) :npm install vue-router3 Vue 3 (使用 Vue Router 4) :npm insta…...
python借助elasticsearch实现标签匹配计数
给定一组标签 [{“tag_id”: “1”, “value”: “西瓜”}, {“tag_id”: “1”, “value”: “苹果”}],我想精准匹配到现有的标签库中存在的标签并记录匹配成功的数量。 标签id(tag_id)标签名(tag_name)标签值(tag_name )1水果西瓜1水果苹果1水果橙子2动物老虎 …...

Yolo-world+Python-OpenCV之摄像头视频实时目标检测
上一次介绍了如何使用最基本的 Yolo-word来做检测,现在我们在加opencv来做个实时检测的例子 基本思路 1、读取离线视频流 2、将视频帧给yolo识别 3、根据识别结果 对视频进行绘制边框、加文字之类的 完整代码如下: import datetimefrom ultralytics …...

vue-treeselect 的基本使用
vue-treeselect 的基本使用 1. 效果展示2. 安装 插件3. 引入组件4. 代码 1. 效果展示 2. 安装 插件 vue-treeselect是一个树形的下拉菜单,至于到底有多少节点那就要看你的数据源有多少层了,挺方便的。下面这个这个不用多说吧,下载依赖 npm in…...

Vue(二)
文章目录 1.条件渲染1.关于js中的false的判定2.基本介绍3.v-if1.需求分析2.代码实例 4.v-show实现5.v-if与v-show比较6.课后练习 2.列表渲染1.代码实例2.课后练习 3.组件化编程1.基本介绍2.实现方式一_普通方式2.实现方式二_全局组件方式3.实现方式三_局部组件方式 4.生命周期和…...

Python基于深度学习的车辆特征分析系统
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
推理还原的干货
故事的递进还原 从下层故事到上层故事 设定还原 还原的逻辑 隐藏信息拼凑、因果导致果推因、规则还原现象 设计思路: 真解答 真解答的关键信息 推理逻辑链 哪些环节可以被误导 如何把关键信息变成伪解答 解释变形信息 给出识别变形信息的方法或线索 其实看似一个…...

【Redis 神秘大陆】006 灾备方案
六、Redis 灾备方案 6.1 存储方案 6.1.1 基础对比 RDB持久化AOF持久化原理周期性fork子进程生成持久化文件每次写入记录命令日志文件类型二进制dump快照文件文本appendonly日志文件触发条件默认超过300s间隔且有1s内超过1kb数据变更永久性每秒fsync一次文件位置配置文件中指…...

【Java基础】17.异常处理
文章目录 前言一、异常的概念1.异常的3种类型2.支持异常处理的关键字和类 二、Exception 类的层次三、内置异常类1.非检查性异常2.检查性异常类 四、异常处理1.捕获异常2.多重捕获块3.throws/throw 关键字1.throw 关键字2.throws 关键字 3.finally关键字 五、编译时异常处理方式…...

【python】flask结合SQLAlchemy,在视图函数中实现对数据库的增删改查
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...

APIGateway的认证
APIGateway的支持的认证如下: 我们从表格中可以看到,HTTP API 不支持资源策略的功能,另外是通过JWT的方式集成Cognito的。 对于REST API则是没有显示说明支持JWT认证,这个我们可以通过Lambda 自定义的方式来实现。 所以按照这个…...
MacOS Github Push项目 精简版步骤
大白菜教程:小白菜 macOS github提交代码-CSDN博客 步骤1:git init步骤2: touch .gitignore 创建ignore文件 open .gitignore 打开ignore文件 编写ignore文件.idea/ 是文件夹的意思.git/ 也是自动生成的文件夹 也不上传.DS_St…...

Eclipse的基本使用讲解(建项目,建包,建类,写代码(基本语法))新手入门必备
目录 一.介绍eclipse 二.操作Eclipse 1.选择工作空间 2.建项目,建包,建类 1.建项目(两种) 2.建包 3.建类 三.写代码(基本语法) 1.代码操作 2.代码规范 3.代码注释 一.介绍eclipse Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其…...

3D模型处理的并行化
今天我们将讨论如何使用 Python 多进程来处理大量3D数据。 我将讲述一些可能在手册中找到的一般信息,并分享我发现的一些小技巧,例如将 tqdm 与多处理 imap 结合使用以及并行处理存档。 那么我们为什么要诉诸并行计算呢? 使用数据有时会出现…...

盲人安全导航技巧:科技赋能让出行更自如
作为一名资深记者,长期关注并报道无障碍领域的发展动态。今日,我将聚焦盲人安全导航技巧,探讨这一主题下科技如何赋能视障人士实现更为安全、独立的出行。一款融合了实时避障、拍照识别物体及场景功能的盲人出行辅助应用叫做蝙蝠避障…...
问,由于java存在性能上,以及部分功能上的缺点,请问如何正确使用C,C++,Go,这三个语言,提升Java Web项目的性能?
拓展阅读:版本任你发,我用java8 我明白Java虽然在许多方面表现出色,但在某些特定场景下可能会遇到性能瓶颈或功能限制。为了提升Java Web项目的性能,可以考虑将C、C和Go这三种语言用于特定的组件或服务。以下是如何正确使用这些语…...
【信号与系统 - 9】傅里叶变换的性质习题
1 习题 已知 f ( t ) f(t) f(t) 的傅里叶变换为 F ( j w ) F(jw) F(jw) ,求如下信号的傅里叶变换 (1) t ⋅ f ( 3 t ) t\cdot f(3t) t⋅f(3t) 解: f ( 3 t ) ↔ 1 3 F ( j w 3 ) f(3t)\leftrightarrow \frac{1}{3}F(j\frac{w}…...
C#探索之路基础夯实篇(5):语法糖概念解析
C#探索之路基础夯实篇(5):语法糖概念解析 文章目录 C#探索之路基础夯实篇(5):语法糖概念解析1、概念定义2、Lua中的语法糖3、C#中的语法糖4、C中的语法糖5、优缺点辨析6、适用范围7、总结 从之前一开始接触lua的时候开始,开始第一次接触到语法…...

SeaTunnel 与 DataX 、Sqoop、Flume、Flink CDC 对比
产品概述 Apache SeaTunnel 是一个非常易用的超高性能分布式数据集成产品,支持海量数据的离线及实时同步。每天可稳定高效同步万亿级数据,已应用于数百家企业生产,也是首个由国人主导贡献到 Apache 基金会的数据集成顶级项目。 SeaTunnel 主要解决数据集成领域的常见问题:…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...