skynet源码学习-skynet_main入口
核心功能与启动流程
Skynet 的启动入口负责整个框架的初始化和配置加载,其工作流程如下:
Shell脚本启动示例
#!/bin/bash
./skynet /path/to/config.lua
main函数参数处理
int main(int argc, char *argv[]) {
const char * config_file = NULL ;
// 检查参数
if (argc > 1) {
config_file = argv[1]; // 使用第一个参数作为配置文件
} else {
// 无配置文件时报错
fprintf(stderr, "Need a config file. Please read skynet wiki : https://github.com/cloudwu/skynet/wiki/Config\n"
"usage: skynet configfilename\n");
return 1;
}
// 全局初始化
skynet_globalinit(); // 初始化全局资源
skynet_env_init(); // 初始化环境变量系统
//信号处理
sigign(); // 忽略SIGPIPE信号,防止网络断开导致进程退出
struct skynet_config config;
#ifdef LUA_CACHELIB
// init the lock of code cache
luaL_initcodecache();
#endif
// 创建Lua虚拟机
struct lua_State *L = luaL_newstate();
luaL_openlibs(L); // 加载Lua标准库
// 加载并执行配置加载器
int err = luaL_loadbufferx(L, load_config, strlen(load_config), "=[skynet config]", "t");
assert(err == LUA_OK);
lua_pushstring(L, config_file);
err = lua_pcall(L, 1, 1, 0); // 执行配置加载
if (err) {
fprintf(stderr,"%s\n",lua_tostring(L,-1));
lua_close(L);
return 1;
}
// 这里处理将lua配置加载并设置到env环境变量中
_init_env(L);
lua_close(L);
// 配置解析处理
config.thread = optint("thread",8); // 默认8线程
config.module_path = optstring("cpath","./cservice/?.so");
config.harbor = optint("harbor", 1); // 默认节点ID=1
config.bootstrap = optstring("bootstrap","snlua bootstrap");
config.daemon = optstring("daemon", NULL); // 守护进程配置
config.logger = optstring("logger", NULL); // 日志文件
config.logservice = optstring("logservice", "logger"); // 日志服务
config.profile = optboolean("profile", 1); // 默认开启性能分析
skynet_start(&config); // 启动skynet核心
skynet_globalexit(); // 释放全局资源
}
其他相关联函数解析
1. 配置加载器解析
static const char * load_config = "\
local result = {}\n\
local function getenv(name) return assert(os.getenv(name), [[os.getenv() failed: ]] .. name) end\n\
local sep = package.config:sub(1,1)\n\
local current_path = [[.]]..sep\n\
local function include(filename)\n\
local last_path = current_path\n\
local path, name = filename:match([[(.*]]..sep..[[)(.*)$]])\n\
if path then\n\
if path:sub(1,1) == sep then -- root\n\
current_path = path\n\
else\n\
current_path = current_path .. path\n\
end\n\
else\n\
name = filename\n\
end\n\
local f = assert(io.open(current_path .. name))\n\
local code = assert(f:read [[*a]])\n\
code = string.gsub(code, [[%$([%w_%d]+)]], getenv)\n\
f:close()\n\
assert(load(code,[[@]]..filename,[[t]],result))()\n\
current_path = last_path\n\
end\n\
setmetatable(result, { __index = { include = include } })\n\
local config_name = ...\n\
include(config_name)\n\ -- 加载主配置文件
setmetatable(result, nil)\n\
return result\n\
";
配置加载器是一个Lua代码字符串,核心功能:
- 支持include指令嵌套配置文件
- 支持$VAR形式的环境变量替换
- 构建配置表并返回
2. 环境变量设置
static void
_init_env(lua_State *L) {
lua_pushnil(L); /* first key */
while (lua_next(L, -2) != 0) {
int keyt = lua_type(L, -2);
if (keyt != LUA_TSTRING) {
fprintf(stderr, "Invalid config table\n");
exit(1);
}
const char * key = lua_tostring(L,-2);
// 根据类型设置环境变量
if (lua_type(L,-1) == LUA_TBOOLEAN) {
int b = lua_toboolean(L,-1);
skynet_setenv(key,b ? "true" : "false" );
} else {
const char * value = lua_tostring(L,-1);
if (value == NULL) {
fprintf(stderr, "Invalid config table key = %s\n", key);
exit(1);
}
skynet_setenv(key,value);
}
lua_pop(L,1);
}
lua_pop(L,1);
}
3. 配置解析函数
- optint - 解析整数配置
static int optint(const char *key, int opt) {
const char * str = skynet_getenv(key);
if (str == NULL) {
// 设置默认值
char tmp[20];
sprintf(tmp,"%d",opt);
skynet_setenv(key, tmp);
return opt;
}
return strtol(str, NULL, 10); // 转换字符串为整数
}
- optboolean - 解析布尔配置
static int optboolean(const char *key, int opt) {
const char * str = skynet_getenv(key);
if (str == NULL) {
// 设置默认值
skynet_setenv(key, opt ? "true" : "false");
return opt;
}
return strcmp(str,"true")==0; // 检查是否为"true"
}
- optstring - 解析字符串配置
static const char * optstring(const char *key,const char * opt) {
const char * str = skynet_getenv(key);
if (str == NULL) {
if (opt) {
skynet_setenv(key, opt); // 设置默认值
opt = skynet_getenv(key);
}
return opt;
}
return str;
}
核心配置项解析
skynet_config结构
struct skynet_config {
int thread; // 工作线程数
const char *module_path; // C服务模块路径
int harbor; // 节点ID
const char *bootstrap; // 引导服务
const char *daemon; // 守护进程配置
const char *logger; // 日志文件
const char *logservice; // 日志服务
int profile; // 性能分析开关
};
典型配置文件分析
config.lua示例
-- 基础配置
thread = 8
harbor = 1
daemon = "./skynet.pid" -- 守护进程模式
logger = "logs/error.log" -- 错误日志
-- 服务路径配置
cpath = "./cservice/?.so" -- C服务路径
lualoader = "./lualib/loader.lua" -- Lua加载器
-- 引导服务
bootstrap = "snlua bootstrap" -- 启动引导服务
start = "main" -- 主入口脚本
-- 自定义配置
mysql_host = "$DB_HOST" -- 使用环境变量
cluster_nodes = {
"node1",
"node2",
include "nodes.lua" -- 包含子配置
}