在Lua中「優雅」地使用Protobuf

2021-10-24 03:54:12 字數 2200 閱讀 6603

protoc-gen-lua:

這個庫的用法和c++版本的比較接近,通過工具生成每個message的**,在lua裡面new乙個message出來進行賦值,最後通過msg:serializetostring()將其序列化成二進位制。這種使用方式在lua裡面很不方便,沒有了指令碼語言的優勢。

pbc:

lua-protobuf:

這個庫是相對比較滿意的乙個實現,**輕量、介面和pbc類似,自己解析proto協議檔案,傳乙個lua的table可以直接encode成二進位制資料,decode二進位制資料可以直接生成乙個table。因為整個庫都是完全脫離protobuf的**自己手寫的,沒有完整得去讀過它的**,所以也不作太多的評價,因為我個人比較信任官方庫和自己。

因為在序列化submessage的時候需要填乙個「變長」編碼的長度資訊,自己實現的庫這個會是非常的棘手。要麼先算一次submessage的長度(在lua中效率低),要麼是需要將資料「分片」最後再將它們拷貝到一塊連續的記憶體空間,要麼是用定長的方式來相容變長的編碼方式。但是感覺這3種方式都不太滿意,我猜這個庫應該是使用的第二種方式

我不太想對它作太深入的了解,因為我覺得就用protobuf的標準庫,通過它的反射介面來實現和lua的對接實現起來應該很簡單,並且這樣實現出來的bug應該會是比較可控,也可以快速得支援protobuf的新增特性(如支援map等),所以我參照著前人的介面使用protobuf原生的c++庫實現了按照自己的想法實現了乙個lua的庫,實際**應該不到1000行。

我的protolua:

syntax = "proto3";

message person

message phonenumber

repeated phonenumber phones = 4;

mapsubjects = 5;

}

require "protolua"

proto.parse("person.proto")

local player = ,,},

subjects =

}local data = proto.encode("person", player)

local clone = proto.decode("person", data)

local data = proto.pack("person", player.name, player.id, player.email, player.phones, player.subjects)

local name, id, email, phones, subjects = proto.unpack("person", data)

用法也比較類似,同時支援proto2和proto3,匯出了幾個lua的介面,parse、encode、decode、pack、unpack。或者直接在網路收發包那裡直接呼叫c函式來pack、unpack可以少一次記憶體拷貝。我寫的**主要也就是通過協議名字找到對應的協議描述descriptor*,然後遍歷它的fields,通過欄位名從lua的table中取值然後在用protobuf的反射介面給message賦值,最後再呼叫message->serializetostring()來序列化,反序列化的**剛好相反。

實際應用中是長這個樣子的:

message cs_account 

message cs_login_req

message cs_login_rsp

}

function net.cs_login_req( ss, openid, token )

log_debug("cs_login_req", ss.number, openid, token)

local result, account = dbagent.login(openid, token)

ss.cs_login_rsp(result, account)

end

新加一條協議伺服器只需要找個地方實現乙個net.cs***_req() 函式,並且通過ss.cs_***_rsp()來給客戶端回包,引數順序都是按協議的字段num順序一一對應的。訊息註冊、派發這些**都不需要,只需要專注於業務邏輯的實現,可以大大提高開發效率。按照同樣的封裝思路也可以將角色資料根據proto的描述資訊將它寫入到mysql、mongodb、redis中,這樣整個伺服器的資料和邏輯就都在lua裡了,熱跟新修復bug、不停機維護都可以在這個的基礎上輕易實現。

優雅地使用Android ViewPager2

viewpager2 是 viewpager 庫的改進版本,可提供增強型功能並解決viewpager的一些問題 viewpager有兩個弊端 1 不能關閉預載入,2 更新adapter不生效。我們在載入資料的時候,viewpager缺省會幫我們預載入前後兩個頁面的資料,但是這兩個view是不可見的,...

在 Vim 中優雅地查詢和替換

harttle land 總有人問我 vim 中能不能查詢,當然能!而且是超級強的查詢!這篇文章來詳細介紹 vim 中查詢相關的設定和使用方法。包括查詢與替換 查詢游標所在詞 高亮前景 背景色 切換高亮狀態 大小寫敏感查詢等。在normal模式下按下 即可進入查詢模式,輸入要查詢的字串並按下回車。v...

如何優雅地在Storyboard中設定圓角

1 view.layer cornerradius 5 對於 storyboard 狂魔,一般情況下,很多人會先把檢視拉乙個 iboutlet 然後再到awakefromenib 或者viewdidload 方法中去設定圓角,如下 123456 iboutlet weak var customvie...