代码改变世界

调试protobuffer接口的神器——luapb

2014-01-16 19:45  mahisaoo  阅读(5500)  评论(2编辑  收藏  举报

    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"
    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)
   ]]--

    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;
}
 
从上面的例子中可以看到,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)
 
以上的这部分代码实现的是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)