SRS的启动过程main—SRS源码分析
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
阅读开源项目的代码,有一些技巧与经验分享给大家。
1,首先不要从头文件一个一个看,想一下子把所有变量的含义都搞明白。我以前也用这个方式,后来发现效率太低。变量的含义跟作用应该是要从代码逻辑里面一点点调试来想出来的。基本上,一些比较复杂的变量,你很难从头文件的注释就能立马看懂它的含义。
2,直接找到 main 入口函数,然后直接往下读。用到哪个变量 函数,你再具体去看特定的变量跟函数。用到再看是提高学习效率的方法之一。
但是大项目,肯定是有很多逻辑分支的,所以你需要控制好主线,先把项目的架构,模块整理出来,然后逐个击破。切记不要这里看一点,那里看一点,不要被 一些不重要的 if
条件分支转移注意力。
3,一定要用调试器来看代码,哪怕你是在看操作系统的代码,也一定要边调试边看代码。因为只有在调试器下,代码才是活的。如果想了解如何调试操作系统的代码,可以加入张银奎老师的读者群。
SRS 服务器的入口函数是 srs_main_server.cpp
的 main 函数,他的整个启动流程如下:
下面简单介绍一下重点函数
1,srs_global_initialize()
srs_global_initialize()
里面就是对很多全局变量进行初始化,例如 日志模块(_srs_log
),配置文件模块(_srs_config
),混合服务模块(_srs_hybrid
),熔断模块(_srs_circuit_breaker
) 等等。
2,SrsThreadPool::setup_thread_locals()
setup_thread_locals()
里面就是简单地调一下 srs_st_init()
,但是也并不简单。由于 SRS 对 StateThreads 协程库进行了多线程改造,所以以前那些 全局变量 都变成了 线程本地变量。
所以,在每次创建线程的时候,都需要调 srs_st_init()
对协程库里面线程本地变量进行初始化。
3,设置协程上下文ID
_srs_context->set_id(_srs_context->generate_id())
这里是设置始祖协程的上下文ID。推荐阅读《SRS的协程ID-SrsContextId》
前面的逻辑可以说是一些杂活,真正的重点是 run_directly_or_daemon()
,这个函数顾名思义就是直接启动 SRS 或者以守护进程启动 SRS。
run_directly_or_daemon()
内部会创建一个新的线程来运行 run_hybrid_server()
函数,这是一个混合服务,RTMP,SRT,WebRTC 等服务都在 hybird_server
里面。
关于线程池 ThreadPool 的设计,请阅读《SRS的线程池介绍SrsThreadPool》
关于 run_hybrid_server()
的内部实现,请阅读《SRS的混合服务SrsHybridServer》