代码目录:
src/目录下核心代码:
- core:核心功能模块,包括日志、配置、错误处理等;
- protocol:实现RTMP、HTTP-FLV、HLS等协议的模块;
- app:应用层的实现,包括流的发布、播放、转码等功能;
- kernel:底层实现,包括网络I/O、多线程处理等;
- main:主层序入口
SRS启动:
main:
// src/main/srs_main_server.cpp
main()
{do_main();
}do_main()
{// 初始化,new创建各种server和实例srs_global_initialize();// 启动线程池?SrsThreadPool::setup_thread_locals();// 加载conf配置_srs_config->parse_options(argc, argv);// 运行主程序run_directly_or_daemon();
}
srs_global_initialize: 初始化各种server
// src/app/srs_app_threads.cpp
srs_global_initialize()
{...// 全局变量 _srs_hybrid:// SrsHybridServer* _srs_hybrid = NULL;_srs_hybrid = new SrsHybridServer();...
}
run_directly_or_daemon: 开始运行
run_directly_or_daemon()
{// 我们没有配置为daemon...int pid = fork();if (pid > 0) {// 父进程直接退出exit(0);}// 继续第二次fork()pid = fork();if (pid > 0) {// 父进程退出exit(0);}// 在子进程中开启执行run_in_thread_pool();
}
run_in_thread_pool
run_in_thread_pool()
{// 初始化线程池_srs_thread_pool->initialize();// 创建run_hybrid_server 工作线程,用于RTMP、RTC server_srs_thread_pool->execute("hybrid", run_hybrid_server, (void*)NULL)// 循环执行线程池中的每个线程:_srs_thread_pool->run();
}
SRS中的线程:
SrsThreadPool 线程池类:
// src/app/srs_app_threads.hpp
class SrsThreadPool {//std::vector<SrsThreadEntry*> threads_;//std::vector<SrsThreadEntry*> hybrids_;
};// 线程池构造函数中,先指定主线程(primordial thread)
// primordial thread并不是调用pthread_create()单独创建的,而是指向了当前调用线程
SrsThreadPool::SrsThreadPool() {entry_ = NULL;lock_ = new SrsThreadMutex();hybrid_ = NULL;// Add primordial thread, current thread itself.SrsThreadEntry* entry = new SrsThreadEntry();threads_.push_back(entry); // 插入到线程池中entry_ = entry;entry->pool = this;entry->label = "primordial";entry->start = NULL;entry->arg = NULL;entry->num = 1;entry->trd = pthread_self(); // 获取当前线程的tidentry->tid = gettid();char buf[256];snprintf(buf, sizeof(buf), "srs-master-%d", entry->num);entry->name = buf;pid_fd = -1;
}
SrsThreadEntry 线程类:
// src/app/srs_app_threads.hpp
class SrsThreadEntry {SrsThreadPool* pool; // 此线程所在的线程池pid_t tid;pthread_t trd;string name;srs_error_t (*start)(void* arg); // 线程入口函数void* arg; // 线程入参
};
_srs_thread_pool是一个全局变量,启动时初始化:
SrsThreadPool* _srs_thread_pool = new SrsThreadPool();
SRS中的Server:
hybrid_server:
// 虚基类,为不同的server子类提供接口
// The hyrid server interfaces, we could register many servers.
class ISrsHybridServer {
public:ISrsHybridServer();virtual ~ISrsHybridServer();
public:virtual srs_error_t initialize() = 0;virtual srs_error_t run(SrsWaitGroup* wg) = 0;virtual void stop() = 0;
};// 管理hybrid server的类
// The hybrid server manager.
class SrsHybridServer : public ISrsFastTimer {
private:std::vector<ISrsHybridServer*> servers; // 管理所有hybrid serverSrsFastTimer* timer20ms_;...virtual void register_server(ISrsHybridServer* svr);
};
SRS中hybrid server类型:
// The SRS server adapter, the master server.
class SrsServerAdapter : public ISrsHybridServer;
// The RTC server adapter.
class RtcServerAdapter : public ISrsHybridServer;
// The srt server adapter, the master server.
class SrsSrtServerAdapter : public ISrsHybridServer;
正如其类名中的“Adapter”所示,这些类是适配类,核心类型是其中真正的server,如SrsServerAdapter中的SrsServer成员、RtcServerAdapter中的SrsRtcServer成员。
SrsServer:
class SrsServerAdapter : public ISrsHybridServer {
private:SrsServer* srs;
public:SrsServerAdapter(); // new创建SrsServervirtual ~SrsServerAdapter();
public:virtual srs_error_t initialize();// 调用SrsServer中的initialize等函数完成初始化,并调用SrsServer->start()virtual srs_error_t run(SrsWaitGroup* wg); virtual void stop();
public:virtual SrsServer* instance();
}; SrsServerAdapter::SrsServerAdapter()
{srs = new SrsServer();
}
SrsServer:
class SrsServer : public ISrsReloadHandler, public ISrsLiveSourceHandler, public ISrsTcpHandler, public ISrsResourceManager, public ISrsCoroutineHandler, public ISrsHourGlass
{
private:SrsHttpServer* http_server; // SrsServer中包含一个HttpServerSrsTcpListener* api_listener_;SrsTcpListener* http_listener_;SrsTcpListener* webrtc_listener_;...
};
SrsRtcServer:
class RtcServerAdapter : public ISrsHybridServer {
private:SrsRtcServer* rtc;
};
gdb:
使用 GDB 调试程序并传递命令行参数:
gdb --args ./objs/srs -c conf/srs.conf
禁用 LeakSanitizer(设置环境变量):
export LSAN_OPTIONS=detect_leaks=0
gdb与fork:
当程序中调用for()创建子进程时,gdb默认只会继续调试父进程,而会“分离”或忽略子进程。
这是因为gdb通常只调试一个进程。
如果需要控制gdb调试指定父进程或子进程,需要通过特定的调试设置来改变这一行为:
(gdb) set follow-fork-mode child # 调试子进程
(gdb) set follow-fork-mode parent # 调试父进程
查看当前follow-fork-mode的值:
(gdb) show follow-fork-mode
常用gdb命令:
c:continue,跳到下一个断点
n:next,调到下一个函数(不进入函数内部)
s:step,进入函数内部
finish:完成函数
r:从头开始
info threads: 查看当前有多少个线程
info inferiors: 查看当前有多少个进程