skynet源码学习-skynet_main入口

发布于:2025-06-20 ⋅ 阅读:(22) ⋅ 点赞:(0)

核心功能与启动流程

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. 配置解析函数

  1. 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); // 转换字符串为整数
}
  1. 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"
}
  1. 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" -- 包含子配置
}

服务启动与运行

核心服务启动流程

在这里插入图片描述

完整启动时序图

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到