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

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

SrsServer

SrsStreamListener

SrsTcpListener

端口侦听过程为

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

[cpp] view plain copy    
  1. if ((ret = _srs_server->listen()) != ERROR_SUCCESS) {
  2. return ret;
  3. }
[cpp] view plain copy    
  1. 在SrsServer的listen()函数如下
[cpp] view plain copy    
  1. <pre name="code" class="cpp">int SrsServer::listen()
  2. {
  3. int ret = ERROR_SUCCESS;
  4. if ((ret = listen_rtmp()) != ERROR_SUCCESS) {
  5. return ret;
  6. }
  7. if ((ret = listen_http_api()) != ERROR_SUCCESS) {
  8. return ret;
  9. }
  10. if ((ret = listen_http_stream()) != ERROR_SUCCESS) {
  11. return ret;
  12. }
  13. if ((ret = listen_stream_caster()) != ERROR_SUCCESS) {
  14. return ret;
  15. }
  16. return ret;
  17. }
[cpp] view plain copy    
  1. listen_rtmp()会建立一个rtmp的steamlistener
[cpp] view plain copy    
  1. <pre name="code" class="cpp">int SrsServer::listen_rtmp()
  2. {
  3. int ret = ERROR_SUCCESS;
  4. // stream service port.
  5. std::vector<std::string> ip_ports = _srs_config->get_listens();
  6. srs_assert((int)ip_ports.size() > 0);
  7. close_listeners(SrsListenerRtmpStream);
  8. for (int i = 0; i < (int)ip_ports.size(); i++) {
  9. SrsListener* listener = new SrsStreamListener(this, SrsListenerRtmpStream);
  10. listeners.push_back(listener);
  11. std::string ip;
  12. int port;
  13. srs_parse_endpoint(ip_ports[i], ip, port);
  14. if ((ret = listener->listen(ip, port)) != ERROR_SUCCESS) {
  15. srs_error("RTMP stream listen at %s:%d failed. ret=%d", ip.c_str(), port, ret);
  16. return ret;
  17. }
  18. }
  19. return ret;
  20. }

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

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

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

[cpp] view plain copy    
  1. int SrsStreamListener::listen(string i, int p)
  2. {
  3. int ret = ERROR_SUCCESS;
  4. ip = i;
  5. port = p;
  6. srs_freep(listener);
  7. listener = new SrsTcpListener(this, ip, port);
  8. if ((ret = listener->listen()) != ERROR_SUCCESS) {
  9. srs_error("tcp listen failed. ret=%d", ret);
  10. return ret;
  11. }
  12. srs_info("listen thread current_cid=%d, "
  13. "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d",
  14. _srs_context->get_id(), p, type, listener->fd(), i.c_str(), p);
  15. srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd());
  16. return ret;
  17. }

在这段代码里面。创建了真正的底层监听类

[cpp] view plain copy    
  1. listener = new SrsTcpListener(this, ip, port);

然后调用其listen()函数。代码如下

[cpp] view plain copy    
  1. int SrsTcpListener::listen()
  2. {
  3. int ret = ERROR_SUCCESS;
  4. if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  5. ret = ERROR_SOCKET_CREATE;
  6. srs_error("create linux socket error. port=%d, ret=%d", port, ret);
  7. return ret;
  8. }
  9. srs_verbose("create linux socket success. port=%d, fd=%d", port, _fd);
  10. int reuse_socket = 1;
  11. if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
  12. ret = ERROR_SOCKET_SETREUSE;
  13. srs_error("setsockopt reuse-addr error. port=%d, ret=%d", port, ret);
  14. return ret;
  15. }
  16. srs_verbose("setsockopt reuse-addr success. port=%d, fd=%d", port, _fd);
  17. sockaddr_in addr;
  18. addr.sin_family = AF_INET;
  19. addr.sin_port = htons(port);
  20. addr.sin_addr.s_addr = inet_addr(ip.c_str());
  21. if (bind(_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
  22. ret = ERROR_SOCKET_BIND;
  23. srs_error("bind socket error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);
  24. return ret;
  25. }
  26. srs_verbose("bind socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);
  27. if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) {
  28. ret = ERROR_SOCKET_LISTEN;
  29. srs_error("listen socket error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);
  30. return ret;
  31. }
  32. srs_verbose("listen socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);
  33. if ((_stfd = st_netfd_open_socket(_fd)) == NULL){
  34. ret = ERROR_ST_OPEN_SOCKET;
  35. srs_error("st_netfd_open_socket open socket failed. ep=%s:%d, ret=%d", ip.c_str(), port, ret);
  36. return ret;
  37. }
  38. srs_verbose("st open socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);
  39. if ((ret = pthread->start()) != ERROR_SUCCESS) {
  40. srs_error("st_thread_create listen thread error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);
  41. return ret;
  42. }
  43. srs_verbose("create st listen thread success, ep=%s:%d", ip.c_str(), port);
  44. return ret;
  45. }

到此,rtmp的监听端口就建立起来了。

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

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

[cpp] view plain copy    
  1. SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)
  2. {
  3. handler = h;
  4. ip = i;
  5. port = p;
  6. _fd = -1;
  7. _stfd = NULL;
  8. pthread = new SrsReusableThread("tcp", this);
  9. }

这个类的作用是什么呢?首先我们发现, SrsTcpListener 这个类继承了一个线程回调接口ISrsReusableThreadHandler。这个说明可以拥有可以在线程中运行的能力

观察线程类的结构

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

[cpp] view plain copy    
  1. int SrsReusableThread::cycle()
  2. {
  3. return handler->cycle();
  4. }

这个是线程这执行函数。它会调用上层类,具体到我们的例子里,就是 SrsTcpListener 的cycle().看看是什么

[cpp] view plain copy    
  1. int SrsTcpListener::cycle()
  2. {
  3. int ret = ERROR_SUCCESS;
  4. st_netfd_t client_stfd = st_accept(_stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
  5. if(client_stfd == NULL){
  6. // ignore error.
  7. if (errno != EINTR) {
  8. srs_error("ignore accept thread stoppped for accept client error");
  9. }
  10. return ret;
  11. }
  12. srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));
  13. if ((ret = handler->on_tcp_client(client_stfd)) != ERROR_SUCCESS) {
  14. srs_warn("accept client error. ret=%d", ret);
  15. return ret;
  16. }
  17. return ret;
  18. }

原来是accept函数。在有链接后直接上调给上层,具体来讲就是 SrsStreamListener类的 on_tcp_client()函数

[cpp] view plain copy    
  1. int SrsStreamListener::on_tcp_client(st_netfd_t stfd)
  2. {
  3. int ret = ERROR_SUCCESS;
  4. if ((ret = server->accept_client(type, stfd)) != ERROR_SUCCESS) {
  5. srs_warn("accept client error. ret=%d", ret);
  6. return ret;
  7. }
  8. return ret;
  9. }

欧耶,这下调用到最上层去了。server里,建立一个链接。

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

1)srs的线程模型

2)如何管理各个链接。

这个下一次在摸索

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

srs代码学习(1)--listen建立过程相关推荐

  1. srs代码学习(4)-怎么转发流

    publish的流和play的流怎么连接呢?这个恐怕是最绕的地方了.看了一上午的代码,淹没于各种数据结构与流程之中后,俺终于发现了连接publish和play的关键连个类是 SrsSource Srs ...

  2. srs代码学习(2)- 线程模型

    代码阅读到现在.发现srs有两大类线程.一个是主线程的逻辑. 一个是监听线程簇.结构图如下 一定还有第三种线程模型,负责底层的多路分发.今天还没有发现. 2016.08.25--21:00 仔细阅读了 ...

  3. 程世东老师TensorFlow实战——个性化推荐,代码学习笔记之③推荐过程

    个性化推荐第三部分:推荐过程(完结撒花) 代码来自于知乎:https://zhuanlan.zhihu.com/p/32078473 /代码地址https://github.com/chengston ...

  4. HEVC代码学习:帧间预测——MVP过程中MV的获取、传递及存储

    作为一个视频编码小白,最近开始着手啃HEVC帧间预测的代码,想用博客记录一下自己的学习过程,也想与大家分享.交流一下. HEVC代码的学习主要是参考两位大神岳麓吹雪.NB_vol_1的博客以及HM参考 ...

  5. DL之GRU:GRU算法相关论文、建立过程(基于TF)、相关思路配图集合、TF代码实现

    DL之GRU:GRU算法相关论文.建立过程(基于TF).相关思路配图集合.TF代码实现 目录 GRU算法相关论文 GRU算法建立过程(基于TF) GRU算法的TF代码实现 GRU算法相关论文 GRU是 ...

  6. 深度学习模型建立过程_所有深度学习都是统计模型的建立

    深度学习模型建立过程 Deep learning is often used to make predictions for data driven analysis. But what are th ...

  7. TLS就是SSL的升级版+网络安全——一图看懂HTTPS建立过程——本质上就是引入第三方监管,web服务器需要先生成公钥和私钥,去CA申请,https通信时候浏览器会去CA校验CA证书的有效性...

    起初是因为HTTP在传输数据时使用的是明文(虽然说POST提交的数据时放在报体里看不到的,但是还是可以通过抓包工具窃取到)是不安全的,为了解决这一隐患网景公司推出了SSL安全套接字协议层,SSL是基于 ...

  8. 为什么无法建立过程性能模型?

    在CMMI四五级的软件公司中,建立过程性能模型是一个重点也是一个难点工作,很多公司无法建立过程性能模型,为什么呢? 1)数据不准 比如: Ø 对于评审的会议,评审的参与人有的是来学习的,在统计人数.工 ...

  9. Apollo代码学习(二)—车辆运动学模型

    Apollo代码学习-车辆运动学模型 前言 车辆模型 单车模型(Bicycle Model) 车辆运动学模型 阿克曼转向几何(Ackerman turning geometry) 小结 Apollo( ...

最新文章

  1. ios手机怎么连接adb命令_手机蓝牙怎么连接汽车蓝牙放音乐,车载蓝牙播放器怎么用...
  2. 关于Linux服务器磁盘空间占满问题的解决方法
  3. php 反序列化工具 phpggc 简介
  4. cgroup 介绍 与使用
  5. 指南--安装带GTK前端的 F-Prot(杀毒)
  6. 【转】 SLIC超像素分割详解(一):简介
  7. Html页面上输出不了PHP,在页面上直接输出未经解析的HTML源码
  8. 感到压力时,你秃的是头,而TA秃的是屁股
  9. Style Lessons in Clarity and Grace (11th Edition)中文翻译
  10. 如何将FAT32分区直接转为NTFS分区
  11. flex 实现图片播放 方案二 把临时3张图片预加载放入内存
  12. Python Flask高级编程
  13. Centos7配置软RAID+LVM
  14. 英文摘要写作要点及指导
  15. linux显示文件后缀名命令,Linux学习笔记(ctrl命令find命令文件后缀名)
  16. 50个查询系列-第13个查询:把“SC”表中“叶平”老师教的课的成绩都更改为此课程的平均成绩;...
  17. 学会 Python 到底能干嘛?我们整理了 7 大工作方向 + 170 个项目课程给你
  18. 白话空间统计二十五:空间权重矩阵外篇:功能地理学
  19. AD629测量负载电流的电路原理详解——精妙绝伦的电路设计
  20. SC92F8003读24C64程序

热门文章

  1. JDK自带监控工具 jps、jinfo、jstat、jmap、jconsole
  2. hibernate的映射文件字段长度和数据库里面的字段长度
  3. Lync在Internet上无法登录问题之一
  4. CSS+DIV-CSS滤镜的应用
  5. vs2008界面查看
  6. 联想杯 - Gentle Jena(单调栈)
  7. HDU - 4612 Warm up(边双缩点+树的直径)
  8. 无向图缩点:tarjan点双与边双缩点(模板)
  9. POJ - 3250 Bad Hair Day(单调队列/单调栈)
  10. python 读取鼠标选中文本_木辛老师的编程课堂:Python和Qt之页面布局实战篇(一)...