SRS作为国人开发的一款高性能流媒体服务器,SRS的定位是运营级的互联网直播服务集群。想必大部分人都使用过,但是很多人也仅仅是停留在会使用的层面,正如原作者所说的,SRS是可以进行二次开发的,那么关于服务器整体是如何运转的我觉得对于一个从事流媒体开发者而言事关重要,因此对于SRS源码的解读就势在必行。
SRS目前的代码量已经达到十几万行,在linux系统下面阅读代码必定不方便,为了方便代码的阅读,我们可以采用本地的IDE进行阅读,作者采用的是Visual Studio 2019来阅读代码
下面就开始我们的源码阅读——SRS服务器的启动流程
阅读源码一般是先掌握整体思路,然后再抠细节。SRS服务器是C++写的,因此首先想到的是去寻找main()函数,SRS服务器的主程序是在 srs_main_server下,如下
int main(int argc, char** argv) {
srs_error_t err = do_main(argc, argv);
if (err != srs_success){
srs_error("Failed, %s", srs_error_desc(err).s_str());
}
int ret = srs_error_code(err);
srs_freep(err);
return ret;
}
本文并不会一行行代码的解读,而是以一个大局观来解读整个SRS服务器在启动阶段的是如何操作的。
SRS服务器在启动阶段主要涉及配置文件config,日志文件log,启动服务server这三方面。按照源码的顺序,可以分为一下步骤
1、检查解析启动命令参数
if ((err = _srs_config->parse_options(argc, argv)) != srs_success){...}
// change the work dir and set cwd. current work dictionary
int r0 = 0;
string cwd = _srs_config->get_work_dir();
if (!cwd.empty() && cwd != "./" && (r0 = chdir(cwd.c_str())) == -1) {...}
if ((err = _srs_config->initialize_cwd()) != srs_success) {...}
检查解析启动命令参数主要利用的是下面这三个函数
parse_options():参数分析,提供一些帮助命令例如 -h等等
get_work_dir():工作路径获取
initialize_cwd():初始化工作路径
2、初始日志接口
// config parsed,initialize log.
if ((err = srs_log->initialize()) != srs_success) {
return srs_error_wrap(err, "log initialize");
}
Initialize():配置解析,初始化日志文件
3、检查配置文件是否正确
// we check the config when the log initialized.
if ((err = _srs_config->check_config()) != srs_success) {
return srs_error_wrap(err, "check config");
}
check_config():检查配置文件是否正确
4、创建 SrsServer服务,初始化一些变量
SrsServer* svr = new SrsServer();
SrsAutoFree(SrsServer, svr);
5、通过守护进程daemon检查是否后台运行还是控制台运行
if (!in_daemon) {
if ((err = run_master(svr)) != srs_success) {
return srs_error_wrap(err, "run master");
}
return srs_success;
}
6、初始化st 协程库,信息号管理器
if ((err = svr->initialize_st()) != srs_success) {
return srs_error_wrap(err, "initialize st");
}
if ((err = svr->initialize_signal()) != srs_success) {
return srs_error_wrap(err, "initialize signal");
}
初始化信号管理器信号管理器主要接收外部的一些系统信号;然后做相应的处理,如修改配置后,发送信号,修改重新加载配置标记,主线程根据该标记重新加截配置。