srs代码学习(1)--listen建立过程

来源:互联网 发布:软件供应商资质要求 编辑:程序博客网 时间:2024/05/03 13:35

srs的服务侦听的建立过程。

以rtmp服务为例 srs服务侦听的建立依靠从上到下的三个类。分别是

SrsServer  

SrsStreamListener  

SrsTcpListener


端口侦听过程为

1)main函数中调用全局变量_srs_server的  listen()函数

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. if ((ret = _srs_server->listen()) != ERROR_SUCCESS) {  
  2.         return ret;  
  3.     }  
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. 在SrsServer的listen()函数如下  
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <pre name="code" class="cpp">int SrsServer::listen()  
  2. {  
  3.     int ret = ERROR_SUCCESS;  
  4.       
  5.     if ((ret = listen_rtmp()) != ERROR_SUCCESS) {  
  6.         return ret;  
  7.     }  
  8.       
  9.     if ((ret = listen_http_api()) != ERROR_SUCCESS) {  
  10.         return ret;  
  11.     }  
  12.       
  13.     if ((ret = listen_http_stream()) != ERROR_SUCCESS) {  
  14.         return ret;  
  15.     }  
  16.       
  17.     if ((ret = listen_stream_caster()) != ERROR_SUCCESS) {  
  18.         return ret;  
  19.     }  
  20.       
  21.     return ret;  
  22. }  


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. listen_rtmp()会建立一个rtmp的steamlistener  
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <pre name="code" class="cpp">int SrsServer::listen_rtmp()  
  2. {  
  3.     int ret = ERROR_SUCCESS;  
  4.       
  5.     // stream service port.  
  6.     std::vector<std::string> ip_ports = _srs_config->get_listens();  
  7.     srs_assert((int)ip_ports.size() > 0);  
  8.       
  9.     close_listeners(SrsListenerRtmpStream);  
  10.       
  11.     for (int i = 0; i < (int)ip_ports.size(); i++) {  
  12.         SrsListener* listener = new SrsStreamListener(this, SrsListenerRtmpStream);  
  13.         listeners.push_back(listener);  
  14.           
  15.         std::string ip;  
  16.         int port;  
  17.         srs_parse_endpoint(ip_ports[i], ip, port);  
  18.           
  19.         if ((ret = listener->listen(ip, port)) != ERROR_SUCCESS) {  
  20.             srs_error("RTMP stream listen at %s:%d failed. ret=%d", ip.c_str(), port, ret);  
  21.             return ret;  
  22.         }  
  23.     }  
  24.       
  25.     return ret;  
  26. }  


这个streamlistener并不是真正的底层监听层。只是一个业务封装层。其类的继承顺序如下

在整个代码中,和其相识的类有SrsRtspListener  SrsHttpFlvListener两个类。这种类的主要作用是在底层链接建立有。给不同的上层放回链接信息。

代码走到这一步,侦听的socket还么米有建立起来,看SrsStreamListener的listen()函数

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int SrsStreamListener::listen(string i, int p)  
  2. {  
  3.     int ret = ERROR_SUCCESS;  
  4.       
  5.     ip = i;  
  6.     port = p;  
  7.   
  8.     srs_freep(listener);  
  9.     listener = new SrsTcpListener(this, ip, port);  
  10.   
  11.     if ((ret = listener->listen()) != ERROR_SUCCESS) {  
  12.         srs_error("tcp listen failed. ret=%d", ret);  
  13.         return ret;  
  14.     }  
  15.       
  16.     srs_info("listen thread current_cid=%d, "  
  17.         "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d",  
  18.         _srs_context->get_id(), p, type, listener->fd(), i.c_str(), p);  
  19.   
  20.     srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd());  
  21.   
  22.     return ret;  
  23. }  
在这段代码里面。创建了真正的底层监听类

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. listener = new SrsTcpListener(this, ip, port);  
然后调用其listen()函数。代码如下

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int SrsTcpListener::listen()  
  2. {  
  3.     int ret = ERROR_SUCCESS;  
  4.       
  5.     if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
  6.         ret = ERROR_SOCKET_CREATE;  
  7.         srs_error("create linux socket error. port=%d, ret=%d", port, ret);  
  8.         return ret;  
  9.     }  
  10.     srs_verbose("create linux socket success. port=%d, fd=%d", port, _fd);  
  11.       
  12.     int reuse_socket = 1;  
  13.     if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {  
  14.         ret = ERROR_SOCKET_SETREUSE;  
  15.         srs_error("setsockopt reuse-addr error. port=%d, ret=%d", port, ret);  
  16.         return ret;  
  17.     }  
  18.     srs_verbose("setsockopt reuse-addr success. port=%d, fd=%d", port, _fd);  
  19.       
  20.     sockaddr_in addr;  
  21.     addr.sin_family = AF_INET;  
  22.     addr.sin_port = htons(port);  
  23.     addr.sin_addr.s_addr = inet_addr(ip.c_str());  
  24.     if (bind(_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {  
  25.         ret = ERROR_SOCKET_BIND;  
  26.         srs_error("bind socket error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);  
  27.         return ret;  
  28.     }  
  29.     srs_verbose("bind socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);  
  30.       
  31.     if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) {  
  32.         ret = ERROR_SOCKET_LISTEN;  
  33.         srs_error("listen socket error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);  
  34.         return ret;  
  35.     }  
  36.     srs_verbose("listen socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);  
  37.       
  38.     if ((_stfd = st_netfd_open_socket(_fd)) == NULL){  
  39.         ret = ERROR_ST_OPEN_SOCKET;  
  40.         srs_error("st_netfd_open_socket open socket failed. ep=%s:%d, ret=%d", ip.c_str(), port, ret);  
  41.         return ret;  
  42.     }  
  43.     srs_verbose("st open socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);  
  44.       
  45.     if ((ret = pthread->start()) != ERROR_SUCCESS) {  
  46.         srs_error("st_thread_create listen thread error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);  
  47.         return ret;  
  48.     }  
  49.     srs_verbose("create st listen thread success, ep=%s:%d", ip.c_str(), port);  
  50.       
  51.     return ret;  
  52. }  
到此,rtmp的监听端口就建立起来了。

在仔细看SrsTcpListener类。继承关系如下



这个类中很有趣的有了个线程类SrsReusableThread* pthread,这个线程是什么时候建立的?答案是在构造函数中

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)  
  2. {  
  3.     handler = h;  
  4.     ip = i;  
  5.     port = p;  
  6.   
  7.     _fd = -1;  
  8.     _stfd = NULL;  
  9.   
  10.     pthread = new SrsReusableThread("tcp"this);  
  11. }  
这个类的作用是什么呢?首先我们发现,SrsTcpListener 这个类继承了一个线程回调接口ISrsReusableThreadHandler。这个说明可以拥有可以在线程中运行的能力

观察线程类的结构



很奇怪,SrsReusableThread竟然也继承了一个handler类。这就表示。这个类还是一个封装类,并不是底层的真正的线程类。果然我们发现了其一个变量 internal::SrsThread* pthread,这个应该靠近点底层了吧。先放下不讲。我们是来追这个线程类也我的业务类啥关系的。这时另外一个有意思的变量ISrsReusableThreadHandler* handler,还记得
SrsTcpListener 类么,其有一个ISrsReusableThreadHandler的接口。通过这个接口,把线程和业务链接起来。看看其cycle()函数

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int SrsReusableThread::cycle()  
  2. {  
  3.     return handler->cycle();  
  4. }  
这个是线程这执行函数。它会调用上层类,具体到我们的例子里,就是SrsTcpListener 的cycle().看看是什么

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  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函数。在有链接后直接上调给上层,具体来讲就是SrsStreamListener类的on_tcp_client()函数

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int SrsStreamListener::on_tcp_client(st_netfd_t stfd)  
  2. {  
  3.     int ret = ERROR_SUCCESS;  
  4.       
  5.     if ((ret = server->accept_client(type, stfd)) != ERROR_SUCCESS) {  
  6.         srs_warn("accept client error. ret=%d", ret);  
  7.         return ret;  
  8.     }  
  9.   
  10.     return ret;  
  11. }  
欧耶,这下调用到最上层去了。server里,建立一个链接。


到现在还有两个问题要搞明白:

1)srs的线程模型

2)如何管理各个链接。


这个下一次在摸索



http://blog.csdn.net/ddr77/article/details/52314210

0 0
原创粉丝点击