游戏开发

Skynet服务器框架(一)Linux下的安装和启动

2017-07-25  本文已影响0人  linshuhe1

引言:

一直都是从事客户端的开发工作,最近抽了点时间想了解一下服务器开发的相关知识,一番博客瞎逛之后,发现了一个不错的框架,云风大神的 skynet开源服务器框架,这不仅仅是针对于游戏服务器开发的框架,更是一个通用的服务器基础框架。

Skynet简介:

Skynet 主要工作是管理注册服务,并开启多线程协调服务之间的调用和通讯。

1.框架核心:

根据云风博客的描述,Skynet 的核心功能就是解决一个问题:

把一个符合规范的 C 模块,从 动态库(so文件)中启动起来,绑定一个永不重复(即使模块退出)的数字id做为其 handle模块 被称为 服务(Service),服务间可以自由发送消息。

名字服务:
Skynet 提供了 名字服务,还可以给特定的服务起一个易读的名字,而不是用 id 来指代它。id 和运行时态相关,无法保证每次启动服务,都有一致的 id ,但名字可以。

简而言之,这个框架完成的功能大概如下:
Skynet 只负责把一个数据包从一个服务内发送出去,让同一进程内的另一个服务收到,调用对应的callback 函数处理。它保证,模块的初始化过程,每个独立的 callback 调用,都是 相互线程安全 的。编写服务的人不需要特别的为多线程环境考虑任何问题,专心处理发送给它的一个个数据包。


2.框架优点:

3.单进程:

很多服务器框架在构建之初,就设想着用多进程的方式来解决高并发的问题,但是所带来的问题就是多进程不可避免的进程安全锁,这样的框架经常会因为部分代码的报错而导致死锁或者内存占用不释放等问题。很多优秀的服务器框架都是使用单进程,然后通过线程池来做消息轮询和任务执行的方式来实现的,这样能够避开锁所带来的诸多问题。

Skynet也是单进程的服务器框架,在单一进程上启动一个线程池,其中包括多个 worker 线程 、一个 socket 网络线程和一个 timer 时间线程。当创建了多个 lua服务,每个服务都相当于Erlang中的一个 Actor (可以简单理解为:可以并行运行的对象),每个服务都有自己的消息队列,skynet也有一个全局的消息队列,线程池中的 worker 线程会随机从消息队列中取出消息来执行直到消息队列为空。此外,每个 lua服务 中又可以通过启动多个 coroutine (携程)来实现异步操作的目的。


Skynet下载配置:

要学习开源框架,第一步肯定是先拿来试用一下,然后再取剖析源码,接下来我们就尝试下载Skynet框架,并尝试使用这套开源的框架来搭建一个测试服务器:

1.资源下载:

Github源码地址:cloudwu/skynet
假如当前是在Linux环境下,并已经安装有 git 工具,则可以直接使用 git 指令 git clone 来拉取Github仓库的 Skynet 最新源码:

sudo git clone https://github.com/cloudwu/skynet.git

假如执行正常,输出如下:

linsh@ubuntu:/mnt/Windows$ sudo git clone https://github.com/cloudwu/skynet.git
正克隆到 'skynet'...
remote: Counting objects: 8079, done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 8079 (delta 1), reused 0 (delta 0), pack-reused 8057
接收对象中: 100% (8079/8079), 2.72 MiB | 24.00 KiB/s, done.
处理 delta 中: 100% (5442/5442), done.
检查连接... 完成。

假如还没安装git工具,可以通过以下指令安装(我的操作系统是 Ubuntu14.04.4):

sudo apt-get install git

2.源码目录结构:

关于源码主要目录及其作用如下:

skynet-master
--3rd           //第三方代码,主要生产一些给lua用的so动态库
--example       //示例工程
--lualib        //lua库
--lualib-src    //luaclib:给lua用的c库
--service       //lua服务
--service-src   //csservice:c服务
--skynet-src    //skynet核心c源码主程序
--test          //一些类库和接口调用的客户端用例
--HISTORY.md    //版本更新日志
--LICENSE
--Makefile      //编译脚本
--platform.mk   //运行平台相关(支持Linux、MacOSX、freebsd操作系统)

3.源码编译:

否则会报如下错误:

cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --disable-valgrind
autoconf
./autogen.sh: line 5: autoconf: command not found
Error 0 in autoconf
make[1]: *** [3rd/jemalloc/Makefile] Error 1
make[1]: Leaving directory `/data/skynet'
make: *** [linux] Error 2

否则会报如下错误:

lua.c:83:31: fatal error: readline/readline.h: 没有那个文件或目录
#include <readline/readline.h>
                              ^
compilation terminated.
make[3]: *** [lua.o] 错误 1
make[3]:正在离开目录 `/application/skynet/3rd/lua'
make[2]: *** [linux] 错误 2
make[2]:正在离开目录 `/application/skynet/3rd/lua'
make[1]: *** [3rd/lua/liblua.a] 错误 2
make[1]:正在离开目录 `/application/skynet'
make: *** [linux] 错误 2

4.错误集:

make[2]: *** 警告:文件“Makefile.in”的修改时间在将来1.8e+06

解决方案:

ln -sf libjemalloc.so.2 lib/libjemalloc.so
ln: 无法创建符号链接"lib/libjemalloc.so": 不支持的操作
make[2]: *** [lib/libjemalloc.so] 错误 1
make[2]:正在离开目录 `/mnt/Windows/skynet/3rd/jemalloc'
make[1]: *** [3rd/jemalloc/lib/libjemalloc_pic.a] 错误 2
make[1]:正在离开目录 `/mnt/Windows/skynet'
make: *** [linux] 错误 2

解决方案:
选择其他非共享的目录进行安装,例如直接复制:

sudo cp -r skynet /application/

启动流程:

skynet 由一个或多个进程构成,每个进程被称为一个 skynet 节点。接下来尝试实现 skynet 节点 的启动流程。

1.配置文件Config

上面完成了源码编译,但是运行启动指令的时候,需要传入一个 Config文件 名称作为启动参数,skynet 会读取这个 Config文件 获取一些启动的必要参数,所以在运行程序之前,还需要根据要求修改配置文件,可以参考 example/config 或直接对其进行修改:

root = "./"
thread = 8
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.."examples/?.lua"
lualoader = "lualib/loader.lua"
snax = root.."examples/?.lua;"..root.."test/?.lua"
cpath = root.."cservice/?.so"

不难看出,这个配置文件内存其实是一个lua代码,以 key-value 形式进行赋值,skynet 启动时读取必要配置项,其他项即便用不到也会以字符串的形式存入 env 表中,所有配置项都可通过 skynet.getenv 获取。

另外,你也可以把一些配置选项配置在环境变量中。比如,你可以把 thread 配置在 SKYNET_THREAD 这个环境变量里。你可以在 config 文件中写:

thread=$SKYNET_THREAD

这样,在 skynet 启动时,就会用 SKYNET_THREAD 这个环境变量的值替换掉 config 中的 $SKYNET_THREAD 了。

2.启动Skynet服务:

编译完成后,查询根目录的文件列表,发现生成了一个 skynet 可执行文件:

linsh@ubuntu:/application/skynet$ ls 
3rd       HISTORY.md  lualib      platform.mk  service-src  test
cservice  LICENSE     lualib-src  README.md    skynet
examples  luaclib     Makefile    service      skynet-src

在skynet的根目录运行以下指令 ./skynet examples/config 启动skynet服务:

linsh@ubuntu:/application/skynet$ ./skynet examples/config
[:01000001] LAUNCH logger 
[:01000002] LAUNCH snlua bootstrap
[:01000003] LAUNCH snlua launcher
[:01000004] LAUNCH snlua cmaster
[:01000004] master listen socket 0.0.0.0:2013
[:01000005] LAUNCH snlua cslave
[:01000005] slave connect to master 127.0.0.1:2013
[:01000004] connect from 127.0.0.1:34760 4
[:01000006] LAUNCH harbor 1 16777221
[:01000004] Harbor 1 (fd=4) report 127.0.0.1:2526
[:01000005] Waiting for 0 harbors
[:01000005] Shakehand ready
[:01000007] LAUNCH snlua datacenterd
[:01000008] LAUNCH snlua service_mgr
[:01000009] LAUNCH snlua main
[:01000009] Server start
[:0100000a] LAUNCH snlua protoloader
[:0100000b] LAUNCH snlua console
[:0100000c] LAUNCH snlua debug_console 8000
[:0100000c] Start debug console at 127.0.0.1:8000
[:0100000d] LAUNCH snlua simpledb
[:0100000e] LAUNCH snlua watchdog
[:0100000f] LAUNCH snlua gate
[:0100000f] Listen on 0.0.0.0:8888
[:01000009] Watchdog listen on 8888
[:01000009] KILL self
[:01000002] KILL self

其他资料:

参考:

上一篇下一篇

猜你喜欢

热点阅读