先用gdb查看大致流程
1. rtmp监听线程创建推流线程的过程分析
gdb ./objs/srs
set args -c ./conf/rtmp.conf
b srs_app_listener.cpp:266
r
1 int SrsTcpListener::cycle() 2 { 3 int ret = ERROR_SUCCESS; 4 5 st_netfd_t client_stfd = st_accept(_stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT); 6 7 if(client_stfd == NULL){ 8 // ignore error. 9 if (errno != EINTR) { 10 srs_error("ignore accept thread stoppped for accept client error"); 11 } 12 return ret; 13 } 14 srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd)); 15 16 if ((ret = handler->on_tcp_client(client_stfd)) != ERROR_SUCCESS) { 17 srs_warn("accept client error. ret=%d", ret); 18 return ret; 19 } 20 21 return ret; 22 }
这个函数将accept的client_stfd交给 ISrsTcpHandler去处理
在此处是 SrsStreamListener::on_tcp_client (this=0x8f2f80, stfd=0x8f4b70) at src/app/srs_app_server.cpp:169
在上面代码的第七行下断点
开启推流,断下
执行bt
#0 SrsTcpListener::cycle (this=0x8f2fe0) at src/app/srs_app_listener.cpp:266 #1 0x00000000004ada7d in SrsReusableThread::cycle (this=0x8f3020) at src/app/srs_app_thread.cpp:452 #2 0x00000000004ace3b in internal::SrsThread::thread_cycle (this=0x8f3040) at src/app/srs_app_thread.cpp:207 #3 0x00000000004ad049 in internal::SrsThread::thread_fun (arg=0x8f3040) at src/app/srs_app_thread.cpp:245 #4 0x0000000000535371 in _st_thread_main () at sched.c:327 #5 0x0000000000535ae1 in st_thread_create (start=0x915000, arg=0x3e8, joinable=32767, stk_size=-150456151) at sched.c:591 #6 0x000000000001ff40 in ?? () #7 0x0000000000000000 in ?? ()
SrsStreamListener::on_tcp_client 代码,简单的交给SrsServer类去处理
// SrsStreamListener改名为SrsRtmpListener更合适一些
// 还有SrsRtspListener,SrsHttpFlvListener,SrsUdpStreamListener等
int SrsStreamListener::on_tcp_client(st_netfd_t stfd) { int ret = ERROR_SUCCESS; if ((ret = server->accept_client(type, stfd)) != ERROR_SUCCESS) { srs_warn("accept client error. ret=%d", ret); return ret; } return ret; }
type定义为
std::string srs_listener_type2string(SrsListenerType type) { switch (type) { case SrsListenerRtmpStream: return "RTMP"; case SrsListenerHttpApi: return "HTTP-API"; case SrsListenerHttpStream: return "HTTP-Server"; case SrsListenerMpegTsOverUdp: return "MPEG-TS over UDP"; case SrsListenerRtsp: return "RTSP"; case SrsListenerFlv: return "HTTP-FLV"; default: return "UNKONWN"; } }
此处为RTMP
在SrsStreamListener::SrsStreamListener处下断点
b SrsStreamListener::SrsStreamListener
断下后
bt
#0 SrsStreamListener::SrsStreamListener (this=0x8f2f80, svr=0x8d53e0, t=SrsListenerRtmpStream, __in_chrg=<optimized out>, __vtt_parm=<optimized out>) at src/app/srs_app_server.cpp:133 #1 0x00000000004778c2 in SrsServer::listen_rtmp (this=0x8d53e0) at src/app/srs_app_server.cpp:1082 #2 0x0000000000475866 in SrsServer::listen (this=0x8d53e0) at src/app/srs_app_server.cpp:743 #3 0x000000000053480b in run_master () at src/main/srs_main_server.cpp:398 #4 0x000000000053442b in run () at src/main/srs_main_server.cpp:341 #5 0x00000000005343a9 in main (argc=3, argv=0x7fffffffe618) at src/main/srs_main_server.cpp:334
可以看到 t=SrsListenerRtmpStream,最终处理rtmp client 连接的是
SrsServer::accept_client
int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd) { int ret = ERROR_SUCCESS; int fd = st_netfd_fileno(client_stfd); int max_connections = _srs_config->get_max_connections(); if ((int)conns.size() >= max_connections) { srs_error("exceed the max connections, drop client: " "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd); srs_close_stfd(client_stfd); return ret; } // avoid fd leak when fork. // @see https://github.com/ossrs/srs/issues/518 if (true) { int val; if ((val = fcntl(fd, F_GETFD, 0)) < 0) { ret = ERROR_SYSTEM_PID_GET_FILE_INFO; srs_error("fnctl F_GETFD error! fd=%d. ret=%#x", fd, ret); srs_close_stfd(client_stfd); return ret; } val |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, val) < 0) { ret = ERROR_SYSTEM_PID_SET_FILE_INFO; srs_error("fcntl F_SETFD error! fd=%d ret=%#x", fd, ret); srs_close_stfd(client_stfd); return ret; } } SrsConnection* conn = NULL; if (type == SrsListenerRtmpStream) { conn = new SrsRtmpConn(this, client_stfd); } else if (type == SrsListenerHttpApi) { #ifdef SRS_AUTO_HTTP_API conn = new SrsHttpApi(this, client_stfd, http_api_mux); #else srs_warn("close http client for server not support http-api"); srs_close_stfd(client_stfd); return ret; #endif } else if (type == SrsListenerHttpStream) { #ifdef SRS_AUTO_HTTP_SERVER conn = new SrsResponseOnlyHttpConn(this, client_stfd, http_server); #else srs_warn("close http client for server not support http-server"); srs_close_stfd(client_stfd); return ret; #endif } else { // TODO: FIXME: handler others } srs_assert(conn); // directly enqueue, the cycle thread will remove the client. conns.push_back(conn); srs_verbose("add conn to vector."); // cycle will start process thread and when finished remove the client. // @remark never use the conn, for it maybe destroyed. if ((ret = conn->start()) != ERROR_SUCCESS) { return ret; } srs_verbose("conn started success."); srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret); return ret; }
b SrsServer::accept_client
int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd) { int ret = ERROR_SUCCESS; int fd = st_netfd_fileno(client_stfd); // 成员变量 conns定义为 std::vector<SrsConnection*> conns;
// 判断有没有超出配置里面的max_connections限制,否则直接关闭套接字
int max_connections = _srs_config->get_max_connections(); if ((int)conns.size() >= max_connections) { srs_error("exceed the max connections, drop client: " "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd); srs_close_stfd(client_stfd); return ret; } // avoid fd leak when fork. // @see https://github.com/ossrs/srs/issues/518 if (true) { int val; if ((val = fcntl(fd, F_GETFD, 0)) < 0) { ret = ERROR_SYSTEM_PID_GET_FILE_INFO; srs_error("fnctl F_GETFD error! fd=%d. ret=%#x", fd, ret); srs_close_stfd(client_stfd); return ret; } val |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, val) < 0) { ret = ERROR_SYSTEM_PID_SET_FILE_INFO; srs_error("fcntl F_SETFD error! fd=%d ret=%#x", fd, ret); srs_close_stfd(client_stfd); return ret; } } // FD_CLOEXEC 标志和文件句柄泄漏参考
//http://blog.csdn.net/ustc_dylan/article/details/6930189
// http://blog.csdn.net/chrisniu1984/article/details/7050663
// 根据不同的type,创建不同SrsConnection类,rtmp流为 SrsRtmpConn SrsConnection* conn = NULL; if (type == SrsListenerRtmpStream) { conn = new SrsRtmpConn(this, client_stfd); } else if (type == SrsListenerHttpApi) { #ifdef SRS_AUTO_HTTP_API conn = new SrsHttpApi(this, client_stfd, http_api_mux); #else srs_warn("close http client for server not support http-api"); srs_close_stfd(client_stfd); return ret; #endif } else if (type == SrsListenerHttpStream) { #ifdef SRS_AUTO_HTTP_SERVER conn = new SrsResponseOnlyHttpConn(this, client_stfd, http_server); #else srs_warn("close http client for server not support http-server"); srs_close_stfd(client_stfd); return ret; #endif } else { // TODO: FIXME: handler others } srs_assert(conn); // directly enqueue, the cycle thread will remove the client. conns.push_back(conn); srs_verbose("add conn to vector."); // 开启st线程处理这个连接 // cycle will start process thread and when finished remove the client. // @remark never use the conn, for it maybe destroyed. if ((ret = conn->start()) != ERROR_SUCCESS) { return ret; } srs_verbose("conn started success."); srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret); return ret; }
bt 输出
#0 SrsServer::accept_client (this=0x8d53e0, type=SrsListenerRtmpStream, client_stfd=0x8f4b70) at src/app/srs_app_server.cpp:1241 #1 0x0000000000472150 in SrsStreamListener::on_tcp_client (this=0x8f2f80, stfd=0x8f4b70) at src/app/srs_app_server.cpp:171 #2 0x000000000052cb49 in SrsTcpListener::cycle (this=0x8f2fe0) at src/app/srs_app_listener.cpp:275 #3 0x00000000004ada7d in SrsReusableThread::cycle (this=0x8f3020) at src/app/srs_app_thread.cpp:452 #4 0x00000000004ace3b in internal::SrsThread::thread_cycle (this=0x8f3040) at src/app/srs_app_thread.cpp:207 #5 0x00000000004ad049 in internal::SrsThread::thread_fun (arg=0x8f3040) at src/app/srs_app_thread.cpp:245 #6 0x0000000000535371 in _st_thread_main () at sched.c:327 #7 0x0000000000535ae1 in st_thread_create (start=0x915000, arg=0x3e8, joinable=32767, stk_size=-150456151) at sched.c:591 #8 0x000000000001ff40 in ?? () #9 0x0000000000000000 in ?? ()