luapb和雲風寫的lua-pbc(git://github.com/cloudwu/pbc.git)並不是一個東西。它們最主要的區別是:pbc雖然也不需要把.proto文件生成.js文件后使用,但是它卻需要生成.pb文件;luapb是完全不需要生成任何中間文件,可以直接對.proto文件操作。
luapb是開源的一個小項目,源碼也很小。github的連接為:
https://github.com/zhanjunxiong/luapb。
我在工作中經常遇到要和后端的protobuffer對象調試,后端的程序是C封裝的protobuffer,前端是用protojs(
https://github.com/sirikata/protojs)解析protobuffer對象;在調試的過程中為了能更好的驗證接口,luapb可以快速的驗證;還是直接看代碼吧:
利用luapb動態的填充protobuffer對象的文件simple.lua:
///////////////
require("luapb")
function encodeSimp()
pb.import("simple.proto")
local msg = pb.new("simple.Simple")
msg.name = "jack"
pb.import("simple.proto")
local msg = pb.new("simple.Simple")
msg.name = "jack"
msg.id = 2
msg.email =
"jack@request.com"
msg.longid = 18446744073709551615
--[[ for decode
local resProto = pb.new("simple.Simple")
pb.parseFromString(resProto, decStr)
print("res:",resProto.uid)
print("res:",resProto.uid)
]]--
return pb.serializeToString(msg)
end
return pb.serializeToString(msg)
end
proto文件:simple.proto
package simple;
message Simple {
required string name = 1;
required int32 id = 2;
optional string email = 3;
required uint64 longid = 4;
}
message Simple {
required string name = 1;
required int32 id = 2;
optional string email = 3;
required uint64 longid = 4;
}
從上面的例子中可以看到,luapb的用法比較直觀;適合需要快速開發的場景。似乎太簡單了也不需要多的解釋。
和server端通信的文件send.lua, 通信的方式是zmq,假設在本地的8765端口起了一個server程序:
require("zmq")
function writeFile(file,str)
local f = assert(io.open(file, "w"))
f:write(str)
f:close()
end
function readIO()
local method = os.getenv("REQUEST_METHOD")
local cmd = ""
if method == "POST" then
local len = os.getenv("CONTENT_LENGTH")
cmd = io.read(tonumber(len))
elseif method == "GET" then
cmd = os.getenv("QUERY_STRING")
end
local addr = os.getenv("REMOTE_ADDR")
local uci = luci.model.uci.cursor()
uci:tset("luci","sysauth_info",{ipaddr=addr})
uci:save("luci")
uci:commit("luci")
return cmd
end
function send_one(reqstring)
local cmd = reqstring
if cmd ~="" then
local ctx = zmq.init(1,1,0)
local s = ctx:socket(zmq.REQ)
local path = "tcp://127.0.0.1:8765"
s:connect(path)
s:send(cmd)
local result=s:recv()
writefile(result)
io.write(result)
s:close()
ctx:term()
else
io.write("")
end
end
dofile("simple.lua")
local req = encodeSimp()
local resString = send_one(req)
print("Decode Message:"..resString)
function writeFile(file,str)
local f = assert(io.open(file, "w"))
f:write(str)
f:close()
end
function readIO()
local method = os.getenv("REQUEST_METHOD")
local cmd = ""
if method == "POST" then
local len = os.getenv("CONTENT_LENGTH")
cmd = io.read(tonumber(len))
elseif method == "GET" then
cmd = os.getenv("QUERY_STRING")
end
local addr = os.getenv("REMOTE_ADDR")
local uci = luci.model.uci.cursor()
uci:tset("luci","sysauth_info",{ipaddr=addr})
uci:save("luci")
uci:commit("luci")
return cmd
end
function send_one(reqstring)
local cmd = reqstring
if cmd ~="" then
local ctx = zmq.init(1,1,0)
local s = ctx:socket(zmq.REQ)
local path = "tcp://127.0.0.1:8765"
s:connect(path)
s:send(cmd)
local result=s:recv()
writefile(result)
io.write(result)
s:close()
ctx:term()
else
io.write("")
end
end
dofile("simple.lua")
local req = encodeSimp()
local resString = send_one(req)
print("Decode Message:"..resString)
以上的這部分代碼實現的是lua-zmq的通訊,即利用lua-zmq將動態填充的proto對象發送到server端;反之我們也通過lua-zmq接受server端返回的proto,並用luapb解析。
luapb提供的API有:
new:新建一個pb的對象; 用法: pb.import("simple.proto"); local msg = pb.new("simple.Simple")
import:導入proto文件; 用法: pb.import("simple.proto")
tostring: 轉化成stringpb.serializeToString(msg)
parseFromString:解析成proto對象,用於decode時; 用法:
local resProto = pb.new("lm.test"); pb.parseFromString(resProto, decStr); print("res:",resProto.uid)
serializeToString:序列化proto, 用於encode時; 用法:pb.serializeToString(msg)