0%

从头开始读skynet源码(1)main入口干了什么

使用skynet一年半了。源码也断断续续读了不少,也看了几篇skynet的源码分析。他们都说的很好。但是觉得分析只是给你一个理解代码的观点,但是没个人的理解方式是不一样的,我也写一写我自己的理解。

下面进入正题。

首先,还是要有一个观念,skynet是干嘛的,云风前辈的Skynet 设计综述,wiki什么的都是要读的。然后进入正题。

从我学习开始,我理解的一个C/C++程序都是从main函数开始运行的,skynet也不例外。以下的代码关键部分都带有注释。

**skynet_main.c **

main函数其实就是,解析配置,做一些初始化,然后使用配置去调用启动函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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;

//打开一个lua虚拟机用于解析传入的配置
struct lua_State *L = luaL_newstate();
luaL_openlibs(L); // link lua lib

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;
}
_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");
config.profile = optboolean("profile", 1);

//解析完,关闭用于解析的lua虚拟机
lua_close(L);

//通过配置启动调用skynet_start
skynet_start(&config);
skynet_globalexit();
luaS_exitshr();

return 0;
}

skynet_start.c

skynet_start做的就是继续初始化,这里需要注意的是bootstrap,这里通过配置可以知道,其实是启动的是snlua(用C写的模块),之后所有的lua服务都是通过snlua启动的(snlua加载lua文件))先记着,之后再分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void 
skynet_start(struct skynet_config * config) {
// register SIGHUP for log file reopen
// 这里处理一些信号的问题。
struct sigaction sa;
sa.sa_handler = &handle_hup;
sa.sa_flags = SA_RESTART;
sigfillset(&sa.sa_mask);
sigaction(SIGHUP, &sa, NULL);

//看看是否配置了守护进程
if (config->daemon) {
if (daemon_init(config->daemon)) {
exit(1);
}
}
skynet_harbor_init(config->harbor); // harbor(港口)初始化
skynet_handle_init(config->harbor); // handler初始化,存贮全部的服务句柄
skynet_mq_init(); // 全局队列初始化
skynet_module_init(config->module_path); // C模块初始化
skynet_timer_init(); // 定时器初始化
skynet_socket_init(); // socket初始化
skynet_profile_enable(config->profile);

//启动logger服务
struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);
if (ctx == NULL) {
fprintf(stderr, "Can't launch %s service\n", config->logservice);
exit(1);
}

skynet_handle_namehandle(skynet_context_handle(ctx), "logger");

//启动配置中的bootstrap服务
bootstrap(ctx, config->bootstrap);

//调用start传入配置线程数量
start(config->thread);

// harbor_exit may call socket send, so it should exit before socket_free
skynet_harbor_exit();
skynet_socket_free();
if (config->daemon) {
daemon_exit(config->daemon);
}
}

然后调用,start,这是整个逻辑的启动,下篇先分析bootstrap。