Skynet 服務器開發 (四) 使用pbc(protobuf)

引言:

假如我們要建立的skynet服務器與客戶端的連接方式爲長連接,且選擇了Google的Protobuf來定製我們的網絡協議,那麼,接下來我們要解決的問題就是:如何在skynet框架中使用socket+protobuf。

API

幾個常用的skynet接口:

*   輸出錯誤信息:          skynet.error(...)
*   獲取本地服務句柄方式:   skynet.localname(...)
*   設置定時器方式:        skynet.timeout(...)
*   skynet強制退出方式:    skyname.abort()
*   服務開始方式:          skynet.start(...)
*   服務註銷方式:          skynet.exit()
*   發送原始文本消息方式:   skynet.core.send(...)

更多skynet.lua的API解析可以參考:skynet API:skynet.lua

protobuf在skynet中使用:

 

一、 linux 環境安裝protobuf

$ sudo apt-get install protobuf-c-compiler protobuf-compiler

輸入protoc --version 
libprotoc 2.5.0

二、安裝protobuf環境,安裝步驟如下:

 

1. 下載protobuf

protobuf下載頁面 https://github.com/protocolbuffers/protobuf/releases/tag/v2.5.0
在此頁面選擇合適的版本,我選擇的是最新的2.5.0

2. 解壓

tar -zxf protobuf-2.5.0.tar.gz

3. 跳轉到解壓後的目錄

cd  protobuf-2.5.0

4. 設置編譯目錄

./configure --prefix=/usr/local/protobuf
/usr/local/protobuf/ 爲自己配置的編譯安裝目錄

5. 安裝

還是在解壓的目錄下進行

      make

      make check
      make install

6. 配置環境變量

sudo  vim .bash_profile

7. 添加配置文件

export PROTOBUF=/usr/local/protobuf
export PATH=$PROTOBUF/bin:$PATH

PS: 如果第七步數據保存不了可以先切換到root 用戶進行保存

sudo -i

8. 使配置文件生效

source .bash_profile

9. 測試安裝結果

輸入protoc --version 
看到如下結果表示安裝成功:

~ maerfeifei$ protoc --version
libprotoc 3.5.0
 

二、使用pbc動態proto解析庫

由於protobuf的lua版本的支持存在着部分缺陷,爲了避免踩坑,這裏我們直接使用雲風博客中推薦的pbc動態proto解析庫。

1、資源下載:

下載pbc:跟下載skynet源碼一樣,通過git將pbc的源碼克隆到本地:

$ cd skynet/3rd/
$ git clone https://github.com/cloudwu/pbc.git

Cloning into 'pbc'...
remote: Counting objects: 1156, done.
remote: Total 1156 (delta 0), reused 0 (delta 0), pack-reused 1156
Receiving objects: 100% (1156/1156), 302.95 KiB | 310.00 KiB/s, done.
Resolving deltas: 100% (682/682), done.
Checking connectivity... done.

編譯併合入項目:

2、項目編譯: 
可以在pbc根目錄下運行make指令編譯項目:

linsh@ubuntu:/application/pbc$ sudo make
cd build && ar rc libpbc.a ../build/o/context.o ../build/o/varint.o ../build/o/array.o ../build/o/pattern.o ../build/o/register.o ../build/o/proto.o ../build/o/map.o ../build/o/alloc.o ../build/o/rmessage.o ../build/o/wmessage.o ../build/o/bootstrap.o ../build/o/stringpool.o ../build/o/decode.o
cd build && gcc -O2 -fPIC -Wall -I.. -L. -o addressbook ../test/addressbook.c -lpbc
cd build && gcc -O2 -fPIC -Wall -I.. -L. -o pattern ../test/pattern.c -lpbc
cd build && gcc -O2 -fPIC -Wall -I.. -L. -o pbc ../test/pbc.c -lpbc
cd build && gcc -O2 -fPIC -Wall -I.. -L. -o float ../test/float.c -lpbc
cd build && gcc -O2 -fPIC -Wall -I.. -L. -o map ../test/map.c -lpbc
cd build && gcc -O2 -fPIC -Wall -I.. -L. -o test ../test/test.c -lpbc
cd build && gcc -O2 -fPIC -Wall -I.. -L. -o decode ../test/decode.c -lpbc
protoc -obuild/addressbook.pb test/addressbook.proto
protoc -obuild/descriptor.pb test/descriptor.proto
protoc -obuild/float.pb test/float.proto
protoc -obuild/test.pb test/test.proto

3、修改LUADIR

protobuf 需要找到lua5.3的目錄,skynet 本身就包含了lua5.3,所以指定到正確的目錄skynet/3rd/lua

將pbc/binding/lua53/makefile中的LUADIR改爲../../../lua

 

4、修改CFLAGS

在 pbc/binding/lua53/makefile 的 變量 CFLAGS 中加入 -undefined dynamic_lookup

防止出錯 Undefined symbols for architecture x86_64:,源文件中是沒有這個選項的,雖然在後面的用例中可以正常的執行,但可能這不一定是好的方案。


5、工具編譯: 
用終端進入pbc項目pbc/binding/lua53目錄下面編譯出protobuf.so:

cd pbc/binding/lua53
sudo make
 

linsh@ubuntu:/application/pbc/binding/lua$ sudo make
gcc -O2 -fPIC -Wall -shared -o protobuf.so -I../.. -I/usr/local/src/lua-5.3.0/src -L../../build pbc-lua.c -lpbc
linsh@ubuntu:/application/pbc/binding/lua$ ls
build_ios.sh  Makefile  parser.lua  pbc-lua.c  protobuf.lua  protobuf.so  README.md  test2.lua  test.lua  testparser.lua

可以看到多出了一個protobuf.so輸出文件。

6、整合protobuf.so 和protobuf.lua 到pbc中

編譯成功的話,將protobuf.so放在config文件中lua_cpath項配置的目錄下面,同時將protobuf.lua放在config文件lua_path配置的目錄下,就可以調用protobuf中的庫方法。我當前項目這兩項的配置如下:

lua_path = root.."lualib/?.lua;"..root.."lualib/?/init.lua"
lua_cpath = root .. "luaclib/?.so"

則移動文件命令可以如下:

sudo cp protobuf.so /application/skynet/luaclib
sudo cp protobuf.lua /application/skynet/lualib

三、測試

1、生成proto文件

先在項目根目錄下創建一個protos文件夾,用來存放協議文件,創建一個Person.proto協議文件,內容如下:

sudo mkdir protos
cd protos
sudo vi Person.proto

協議文件的內容如下:

packae cs;
message Person {
required string name = 1;
required int32 id = 2;        // Unique ID number for this person.
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}

2、將協議文件導出爲.pb格式:

linsh@ubuntu:/application/skynet/protos$ sudo protoc --descriptor_set_out Person.pb Person.proto
linsh@ubuntu:/application/skynet/protos$ ls
Person.pb  Person.proto

目錄下多出了一個對應的.pb文件。

3、使用.pb 文件

在lua中註冊對應的協議文件:

引入protobuf.lua:

local pb = require "protobuf"

註冊.proto協議文件所對應的.pb文件,註冊方法有兩種:

方法一:直接註冊文件:

pb.register_file "Person.pb"

方法二:通過io讀取文件,然後再獲取文本內容進行註冊:

file = io.open("Person.pb","rb")
buffer = file:read "*a"
file:close()
pb.register(buffer)

4、完整用例
通過 encode 和 decode 兩個接口來實現編碼和解碼,完整測試腳本:

local skynet = require "skynet"
local protobuf = require "protobuf"

skynet.start(function()
    protobuf.register_file "./protos/Person.pb"
    skynet.error("註冊協議文件:Person.pb")
    stringbuffer = protobuf.encode("cs.Person",
    {
        name = "linsh",
        id = 1,
    })
    local data = protobuf.decode("cs.Person",stringbuffer)
    skynet.error("數據編碼:name="..data.name..",id="..data.id)
end)

運行正確的結果:

[:0100000c] 註冊協議文件:Person.pb
[:0100000c] 數據編碼:name=linsh,id=1

除外,雲風還自定義了一套協議格式sproto,據說比protobuf還要簡單。

參考:

cocos2dx和skynet通信
lua-protobuf 使用說明
lua pbc 
pbc/binding/lua/README.md
skyne use pbc protobuf
--------------------- 
作者:河樂不爲 
來源:CSDN 
原文:https://blog.csdn.net/linshuhe1/article/details/70186603 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章