配置Skynet并使用pbc与客户端通信

  1. 1. clone
  2. 2. 编译配置Skynet
    1. 2.1. Config
  3. 3. 编译pbc
    1. 3.1. 编译项目
    2. 3.2. Lua bindings
  4. 4. 测试
    1. 4.1. 编译protobuf
    2. 4.2. 魔改
    3. 4.3. agent.lua
    4. 4.4. 开启客户端测试
  5. 5. 总结
  6. 6. 参考

最近终于是调通了客户端和Skynet。虽然过程中几经坎坷,而且对socket依然一知半解,但是既然客户端和服务器已经能进行正常通信,那么就可以算是一个阶段性的成果了。

为了防止健忘的我忘记怎么配置服务器,我决定吧服务器配置的方法记录在这。仅作我自己使用,如果对你也有帮助那当然更好。

clone

Skynetpbc都是云风大佬的作品,分别放在了两个Git仓库中。

首先将两个项目都克隆下来进行构建。

1
2
git clone git@github.com:cloudwu/skynet.git
git clone git@github.com:cloudwu/pbc.git

编译配置Skynet

按照项目的说明,在Skynet根目录下执行对应平台的make命令,需要一点时间。

1
make linux

Config

编译完成之后,首先在Skynet的目录下新建一个config文件,按照Skynet官方Wiki介绍的配置就好。我习惯是在根目录下新建一个gamelogic文件夹放自己的lua脚本,所以我魔改了一点点官方的配置就能直接用。

1
2
3
4
5
6
7
8
9
10
11
12
13
root = "./"
thread = 4
logger = nil
harbor = 1
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "main" -- main script
bootstrap = "snlua bootstrap" -- The service for bootstrap
standalone = "0.0.0.0:2013"
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."gamelogic/?.lua"
lualoader = "lualib/loader.lua"
-- snax = root.."examples/?.lua;"..root.."test/?.lua"
cpath = root.."cservice/?.so"

编译pbc

编译项目

直接在pbc的根目录下执行make,如果所有环境都打好了,你应该会看到类似的输出。执行protoc的时候可能会出现没有声明版本的警告,那个影响不大。

1
2
3
4
5
6
7
8
9
10
11
root@linux:~/GameServer/pbc# make
mkdir -p build/o
gcc -O2 -fPIC -Wall -c -Isrc -I. -o build/o/context.o -MMD src/context.c
...
...
...
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

如果提示protoc命令未找到,说明你还没装protobuf环境,用这个指令安装。

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

Lua bindings

pbc项目贴心的为我们提供了工具,可以直接编译出动态库和lua脚本用于Skynet,这里我直接用这个。

用这个之前有两个地方要特别注意。第一,机器上必须要安装有对应的lua版本。第二,Makefile文件中的LUADIR应该指向lua的安装地址。

如果以上两点都没问题,就直接执行下面这个命令。

1
2
cd pbc/binding/lua53
sudo make

编译成功后,把同目录下的protobuf.lua和刚刚生成的protobuf.so分别放在Skynet的lualibluaclib目录下,就能调用了。

测试

编译protobuf

随便瞎写了一个测试文件,命名为test.proto。

1
2
3
4
5
6
7
8
syntax="proto3";

package hello;

message UserInfo{
int32 id = 1;
string name = 2;
}

编译一下

1
sudo protoc --descriptor_set_out gen/test.pb test.proto

魔改

这里我直接把Skynet自带的例子里的watchdog.lua main.lua agent.lua拿来魔改一下,把原来的sproto协议改成pbc,放在gamelogic的目录下。

include
使用前先引入protobuf库,编解码之前一定要注册.pb文件,我这里为了方便就先放在CMD.start()了。

1
2
3
local protobuf = require "protobuf" -- 放在源代码开头

protobuf.register_file "./protos/gen/test.pb" -- 放在你觉得合理的地方

decode

1
2
3
4
5
6
unpack = function (msg, sz)
str1 = skynet.tostring(msg, sz)
local data = protobuf.decode("hello.UserInfo", str1)
skynet.error("id:"..data.id..";name:"..data.name)
-- return host:dispatch(msg, sz)
return data.id

encode

1
2
3
4
5
6
7
8
9
10
skynet.fork(function()
while true do
send_package(
protobuf.encode("hello.UserInfo", {
id = 233, name = "Hello this is Skynet"
})
)
skynet.sleep(500)
end
end)

agent.lua

测试用的agent.lua具体逻辑大概是,如果有客户端连接,就启动一个新的任务去给客户端发送“心跳包”。如果客户端上发了数据,就解包,然后打印出来。我魔改了一下心跳包给我测试protobuf的s2c。watchdog.luamain.lua的代码基本与官方样例中保持一致。

全部的agent.lua代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
local skynet = require "skynet"
local socket = require "skynet.socket"
local sproto = require "sproto"
-- local sprotoloader = require "sprotoloader"
local protobuf = require "protobuf"

local WATCHDOG
local host
local send_request

local CMD = {}
local client_fd

local 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)
str1 = skynet.tostring(msg, sz)
local data = protobuf.decode("hello.UserInfo", str1)
skynet.error("id:"..data.id..";name:"..data.name)
return "return:id:"..data.id..";name:"..data.name
end,
dispatch = function (fd, _, type, ...)
-- place game logic here.
end
}

function CMD.start(conf)
local fd = conf.client
local gate = conf.gate
WATCHDOG = conf.watchdog
protobuf.register_file "./protos/gen/test.pb"
skynet.fork(function()
while true do
send_package(
protobuf.encode("hello.UserInfo", {
id = 233, name = "Hello this is Skynet"
})
)
skynet.sleep(500)
end
end)

client_fd = fd
skynet.call(gate, "lua", "forward", fd)
end

function CMD.disconnect()
-- todo: do something before exit
skynet.exit()
end

skynet.start(function()
skynet.dispatch("lua", function(_,_, command, ...)
skynet.trace()
local f = CMD[command]
skynet.ret(skynet.pack(f(...)))
end)
end)

开启客户端测试

客户端参考我的另一篇文章。

根据我上面在agent.lua中写的代码,客户端每五秒会收到一次消息。
TestClient

客户端向服务端发送消息,也可以被正常收到。这里要注意Skynet的默认网关的前两个字节代表长度,第一次搞的时候一直不知道,卡了很久。

1
[:0100000e] return:id:233;name:TypeAlpha

总结

Skynet通信基本上已经被我调通了,也就是说游戏服务器入门的部分已经算是被我掌握了。虽然最后跑起来的代码只能说勉勉强强能用,而且什么突发事件都应对不了,稍微出点问题就整个垮掉。现在的水平如果是以制作网络游戏为目的,那恐怕还差得远呢,只能说还有很多要学的。

参考

Skynet服务器框架 使用pbc(protobuf)
编译pbc主要参考了这篇文章,CSDN这篇是转载的,原作者我已经找不到了。