凡科做网站不好,宁波做网站的大公司有哪些,seo排名助手,wordpress 免插件统计一、安装protobuf 下面的操作方法都是在 centos 环境下操作 #下载 Protocol Buffers 源代码#xff1a;
#您可以从 Protocol Buffers 的 GitHub 仓库中获取特定版本的源代码。使用以下命令克隆仓库
git clone -b v3.20.3 https://github.com/protocolbuffers/protobuf.git#编译…一、安装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 account1;string passwd2;int32 result3;
}
五、编译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 *ac._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/?.solocal 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 datadesc: 将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 tableutillocal dataHelper require protobufDataHelperlocal 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, dont 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 doesnt support request clientendend
}--]]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 packagesend_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/?.lualocal tableutil require tableutilif _VERSION ~ Lua 5.4 thenerror Use lua 5.4
endlocal socket require client.socket
local dataHelper require protobufDataHelperlocal 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 s2 thenreturn nil, textendreturn text:sub(3,2s), text:sub(3s)
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 closedendreturn 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