skynet加载配置文件

看了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入口获取到了配置文件中的值.


参考:

http://www.runoob.com/manual/lua53doc/manual.html#pdf-load

https://blog.csdn.net/rio_dog/article/details/6754778



猜你喜欢

转载自blog.csdn.net/zxm342698145/article/details/80407306