美文网首页skynet
skynet加载配置文件

skynet加载配置文件

作者: 哈罗_aae9 | 来源:发表于2018-08-02 12:06 被阅读0次

    看了skynet加载配置的地方,竟然发现好多知识点,记录下.

    skynet的配置文件是通过命令行传入到进程的,这个比较明了. 仔细读了一下这块代码,发现有不少细节,而且,有些lua函数竟然很少用过,下面就这块代码分析一下.

    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;
        }
    
        luaS_initshr();
        skynet_globalinit();
        skynet_env_init();
    
        sigign();
    
        struct skynet_config config;
    
        struct lua_State *L = lua_newstate(skynet_lalloc, NULL);
        luaL_openlibs(L);   // link lua lib
    
        int err = luaL_loadstring(L, load_config);
        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;
        }
        _init_env(L);
    
        config.thread =  optint("thread",8);
        config.module_path = optstring("cpath","./cservice/?.so");
        config.harbor = optint("harbor", 1);
        config.bootstrap = optstring("bootstrap","snlua bootstrap");
        config.daemon = optstring("daemon", NULL);
        config.logger = optstring("logger", NULL);
        config.logservice = optstring("logservice", "logger");
    
        lua_close(L);
    
        skynet_start(&config);
        skynet_globalexit();
        luaS_exitshr();
        return 0;
    }
    

    加载配置文件通过luaL_loadstring,lua_pushstring,lua_pcall三个lua api来完成.

    luaL_loadstring(load_config)加载一段lua字符串代码,整理后如下:

    local f = assert(io.open(...))
    local code = assert(f:read('*a'))
    local function getenv(name)
        return assert(os.getenv(name), 'os.getenv() failed: config')
    end
    code = string.gsub(code, '%$([%w_%d]+)', getenv)
    f:close()
    local result = {}
    assert(load(code, '=(load)', 't', result))()
    return result
    

    我们注意到io.open的参数是...,其实是通过lua_pushstring(config_file)传递进去的.lua_pcall就是执行这段代码,并有一个返回值.

    执行在上面的代码,读取配置文件的内容. string.gsub()用来查找形如'XXX',一般是系统的环境变量,例如HOME,然后用getenv()函数执行的结果来替换. 这一点有时也挺有用,比如写路径时可以直接引用系统的变量路径值.

    再后面就是load,他的作用是把code字符串作为一个函数体,然后执行.这样说还是不清楚,我们看下一个例子:

    b = 100
    f = load('return b')
    print(f())
    

    f就相当于f = function() return b end,区别是如果b是个local变量,那么在load中则不可见.

    第二个参数'=(load)'在错误消息和调试消息中,用于代码块的名字。 如果不提供此参数,它默认为字符串chunk 。 chunk 不是字符串时,则为 "=(load)" 。字符串't'用于控制代码块是文本还是二进制(即预编译代码块)。 它可以是字符串 "b" (只能是二进制代码块), "t" (只能是文本代码块), 或 "bt" (可以是二进制也可以是文本)。 默认值为 "bt"。result用来接收函数的上值. 所谓上值就是函数里的全局变量,即配置文件里的形如'thread = 8'的值,都保存在result里, 并且返回result,供下面的c环境中使用.

    接下来就是将上面的result通过skynet_setenv写入到全局的lua虚拟机中.这样全局虚拟机中就有了配置文件中的键值对.skynet_start()函数有个skynet_config类型的参数,他是通过optint,optstring函数从前面说的全局lua虚拟机中获取的. 就这样skynet入口获取到了配置文件中的值.

    相关文章

      网友评论

        本文标题:skynet加载配置文件

        本文链接:https://www.haomeiwen.com/subject/eemjvftx.html