skynet进程的生命周期

示例代码

方便展示项目结构,我将代码例子都放在skynet-guide仓库。

将skynet和skynet-guide放到统一目录下。

$ git clone https://github.com/cloudwu/skynet
$ git clone https://github.com/kasicass/skynet-guide

编译好skynet,之后:

$ cd skynet-guide/02-life-cycle
$ ./tools/bootstrap.sh

bootstrap会从skynet目录复制所需要的文件。

目录结构

正式项目,会规划好目录结构,一眼便知道,哪些是外部依赖库、哪些是项目自身的代码和资源。02-life-cycle演示了一个正式项目的组织结构。

$ tree -L 2
.
├── conf
│   ├── server.conf             # 启动配置
│   └── server-deamon.conf
├── engine                      # 引擎目录(从skynet复制过来的文件)
│   ├── cservice
│   ├── luaclib
│   ├── lualib
│   └── service
├── server                      # 服务端代码目录
│   └── service
│       ├── cat.lua
│       └── main.lua
├── skynet                      # skynet binary
└── tools                       # 初始化、启动脚本
    ├── bootstrap.sh
    └── cleanup.sh

启动配置

skynet启动时,需要传入一个配置文件(一个lua脚本)。

cpath      = "./engine/cservice/?.so"
lua_cpath  = "./engine/luaclib/?.so"
lualoader  = "./engine/lualib/loader.lua"
lua_path   = "./engine/lualib/?.lua;./server/lualib/?.lua"
luaservice = "./engine/service/?.lua;./server/service/?.lua"
snax       = "./server/?.lua"

thread     = 8
logger     = nil
logpath    = "."
harbor     = 1
address    = "127.0.0.1:2526"
master     = "127.0.0.1:2013"
start      = "main"                # script/service/main.lua 
bootstrap  = "snlua bootstrap"     # engine/service/bootstrap.lua
standalone = "0.0.0.0:2013"

lua service的启动流程:

bootstrap 表示引擎启动后,启动的第一个 lua service;然后 bootstrap 中,启动游戏的第一个 service "main"

start      = "main"
bootstrap  = "snlua bootstrap"

$ ./skynet conf/game.conf
[:01000002] LAUNCH snlua bootstrap
...
[:01000009] LAUNCH snlua main
[:0100000a] LAUNCH snlua cat
[:0100000a] CAT: miao~ miao~
[:01000009] KILL self
[:01000002] KILL self
[:0100000a] CAT: bye~
[:0100000a] KILL self

service 间的启动关系

在 main.lua 中,再启动 "cat"。

local skynet = require "skynet"

skynet.start(function()
    skynet.newservice("cat")
    skynet.exit()
end)

cat.lua 中,skynet.fork() 启动另一个 coroutine,跑 cat service 具体的业务

local skynet = require "skynet.manager"

local function cat_main_loop()
    skynet.error("CAT: miao~ miao~")
    skynet.sleep(300) -- 3s
    skynet.error("CAT: bye~")
    skynet.abort()
end

skynet.start(function()
    skynet.fork(cat_main_loop)
end)

skynet的退出机制

看 cat.lua 中

local skynet = require "skynet.manager"

local function cat_main_loop()
    ...
    skynet.abort()
end

每个 service 都是独立的 lua vm,需要独立 require 所需要的功能

skynet.abort()
  │
  ▼
cmd_abort() → skynet_handle_retireall()
  │              │
  │              ├─ retire 服务1 → context_release → delete_context → total--
  │              ├─ retire 服务2 → context_release → delete_context → total--
  │              └─ ... 直到所有 slot 为空
  │
  ▼
total == 0
  │
  ├─ timer 线程: CHECK_ABORT       → break
  │     ├─ skynet_socket_exit()    → socket 线程退出
  │     └─ m->quit=1, broadcast    → worker 线程退出
  │
  ├─ monitor 线程: CHECK_ABORT     → break
  │
  ▼
pthread_join (所有线程)
  │
  ▼
skynet_harbor_exit()
skynet_socket_free()
daemon_exit()        ← 删除 pid 文件
  │
  ▼
进程退出

daemon 方式运行 skynet

在生成环境,都会以 daemon 方式运行服务端进程。对于 skynet,只需要修改下配置文件:

logger     = "./skynet.log"
daemon     = "./skynet.pid"

$ ./skynet conf/server-deamon.conf

$ cat skynet.pid
2827277

$ cat skynet.log
04/06/26 15:32:11.31 [:01000002] LAUNCH snlua bootstrap
04/06/26 15:32:11.32 [:01000003] LAUNCH snlua launcher
04/06/26 15:32:11.32 [:01000004] LAUNCH snlua cmaster
04/06/26 15:32:11.33 [:01000004] master listen socket 0.0.0.0:2013
04/06/26 15:32:11.33 [:01000005] LAUNCH snlua cslave
04/06/26 15:32:11.33 [:01000005] slave connect to master 127.0.0.1:2013
04/06/26 15:32:11.33 [:01000004] connect from 127.0.0.1:41374 4
04/06/26 15:32:11.33 [:01000006] LAUNCH harbor 1 16777221
04/06/26 15:32:11.33 [:01000004] Harbor 1 (fd=4) report 127.0.0.1:2526
04/06/26 15:32:11.33 [:01000005] Waiting for 0 harbors
04/06/26 15:32:11.33 [:01000005] Shakehand ready
04/06/26 15:32:11.33 [:01000007] LAUNCH snlua datacenterd
04/06/26 15:32:11.34 [:01000008] LAUNCH snlua service_mgr
04/06/26 15:32:11.34 [:01000009] LAUNCH snlua main
04/06/26 15:32:11.34 [:0100000a] LAUNCH snlua cat
04/06/26 15:32:11.34 [:0100000a] CAT: miao~ miao~
04/06/26 15:32:11.34 [:01000009] KILL self
04/06/26 15:32:11.34 [:01000002] KILL self