Darwin Streaming Server 核心代码分析
首先,我针对的代码是Darwin Streaming Server 6.0.3未经任何改动的版本。
Darwin Streaming Server从设计模式上看,采用了Reactor的并发服务器设计模式,如果对Reactor有一定的了解会有助于对Darwin Streaming Server核心代码的理解。
Reactor模式是典型的事件触发模式,当有事件发生时则完成相应的Task,Task的完成是通过调用相应的handle来实现的,对于handle的调用是由有限个数的Thread来完成的。
Darwin Streaming Server中定义了一个Task类。Task类有两个典型的方法,一个是Signal,一个是Run。调用Signal把一个Task加入到TaskThread的Task队列中,等待完成,Run就是完成一个任务的handle。基于Task类,定义了三种类型的Task,分别是IdleTask,TimeoutTask,以及普通的Task。
在Darwin Streaming Server中,除了主线程以外,有三种类型的线程,分别是TaskThread,EventThread以及IdleTaskThread:
- TaskThread,TaskThread通过运行Task类型对象的Run方法来完成相应Task的处理。典型的Task类型是RTSPSession和RTPSession。TaskThread的个数是可配置的,缺省情况下TaskThread的个数与处理器的个数一致。等待被TaskThread调用并运行的Task放在队列或者堆中。
- EventThread,EventThread负责侦听套接口事件,在Darwin Streaming Server中,有两种被侦听的事件,分别是建立RTSP连接请求的到达和RTSP请求的到达。对于RTSP连接请求的事件,EventThread建立一个RTSPSession,并启动针对相应的socket的侦听。对于RTSP请求的事件,EventThread把对应的RTSPSession类型的Task加入到TaskThread的队列中,等待RTSP请求被处理。
- IdleTaskThread,IdleTaskThread管理IdleTask类型对象的队列,根据预先设定的定时器触发IdleTask的调度。TCPListenerSocket就是一个IdleTask的派生类,当并发连接数达到设定的最大值时,会把派生自TCPListenerSocket的RTSPListenerSocket加入到IdleTaskThread管理的IdleTask队列中,暂时停止对RTSP端口的侦听,直到被设定好的定时器触发。
核心架构
下图是Darwin Streaming Server核心架构的示意图。在这个示意图中有三种类型的要素,分别是线程,Task队列或者堆,被侦听的事件。图中的文字都是从源代码中copy出来的,便于读者通过查找与源代码对应起来。
图中给出了三个线程,分别是TaskThread::Entry,EventThread::Entry以及IdleTaskThread::Entry。前文已经对这三种线程进行了概要描述。
除了三个线程,图中还有另外五个矩形块。与TaskThread::Entry线程相关联的有两个,分别是TaskThread::fTaskQueue队列和TaskThread::fHeap堆,通过调用Signal被调度等待完成的Task就放在队列或者堆中。与IdleTaskThread::Entry线程相关联的有一个,是IdleTaskThread::IdleHeap堆。与EventThread::Entry相关联的是EventContext::fEventReq,是被侦听的端口。还有一个是TimeoutTaskThread::fQueue队列,它事实上是通过TimeoutTask与TaskThread::Entry相关联。
图中指向线程的连接线表明从队列或者堆中取出Task,而对于EventThread::Entry线程来说,则是被侦听事件的发生。指向被侦听的端口的连接线表明把端口加入侦听,指向Task的队列或堆的连接线,表明把Task加入到队列或者堆中。连接线的文字给出的是相应的函数调用,可以直接在源代码中搜索到。
EventThread
系统启动的时候调用QTSServer::StartTasks()把RTSP服务端口加入到侦听队列中。此时便开始接收客户端的RTSP连接请求了。
在EventThread::Entry中调用select_waitevent函数等待事件的发生,当有事件发生的时候,就通过调用ProcessEvent方法对事件进行相应的处理。注意ProcessEvent是一个虚函数,共有两个实现。EventContext类中实现了ProcessEvent方法,EventContext的派生类TCPListenerSocket中也实现了ProcessEvent方法。
对于建立RTSP连接的请求,调用TCPListenerSocket::ProcessEvent方法来处理,此方法调用RTSPListenerSocket的GetSessionTask方法建立一个RTSPSession,并把相应的套接口加入侦听队列,等待RTSP请求。然后还需调用this->RequestEvent(EV_RE)把建立RTSP连接的请求加入到侦听队列。
对于RTSP连接上的RTSP请求事件,调用的是EventContext::ProcessEvent方法,通过Task的Signal把对应的RTSPSession类型的Task加入到TaskThread::fTaskQueue中等待TaskThread处理。
TaskThread与Task
TaskThread::Entry调用TaskThread::WaitForTask()方法获得下一个需要处理的Task。TaskThread::WaitForTask()首先从TaskThread::fHeap中获得Task,如果TaskThread::fHeap中没有满足条件的Task,则从TaskThread::fTaskQueue中获得Task。
TaskThread::Entry调用Task::Run方法来完成对应的Task,Task::Run方法的返回值类型是SInt64,也即signed long long int类型。TaskThread::Entry根据Task::Run方法的返回值进行不同的处理。对于小于0的返回值,需delete这个Task;对于大于0的返回值,返回值代表了下次处理这个Task需等待的时间,TaskThread::Entry调用fHeap.Insert(&theTask->fTimerHeapElem)把Task插入到堆里,并设定等待时间。对于等于0的返回值,TaskThread::Entry不再理会该Task。
TimeoutTask
从代码中看,TimeoutTaskThread是IdleTask的派生类,分析后发现从TimeoutTaskThread与IdleTask没有任何关系,完全可以从Task派生,修改代码后验证了这个想法。因此TimeoutTaskThread就是一个普通的Task,TimeoutTaskThread通过其Run方法监控一组超时任务,具体的比如RTSP协议或者RTP协议超时。
在系统启动的时候TimeoutTaskThread被加入到TaskThread的队列中,这是通过在StartServer函数中调用TimeoutTask::Initialize()来实现的。TimeoutTaskThread::Run函数的返回值是intervalMilli = kIntervalSeconds * 1000,也就是一个正数,于是TimeoutTaskThread这个Task会加入到TaskThread::fHeap中被周期性的调用。
TimeoutTaskThread::Run方法发现有超时的任务,则通过Signal方法调度这个Task,event为Task::kTimeoutEvent。被管理的这组任务,要有RefreshTimeout的机制。
一次点播请求的处理
为了更好的理解Darwin Streaming Server的架构,我们从客户端发起点播,触发服务器的建立RTSP连接事件的发生开始,看看DSS的工作流程是什么样的。
针对RTSP协议,Darwing Streaming Server在554端口上侦听,当有连接请求到达时,通过accept调用返回一个socket,对应的后续RTSP请求都是通过这个socket来传送的。我们把RTSP相关的事件分成两类,一类是RTSP连接请求,一类是RTSP请求。先来看RTSP连接请求的过程:
- RTSP连接请求到达后,被select_waitevent函数捕获,代码在EventContext.cpp的EventThread::Entry中232行。
- 查找EventThread::fRefTable,获取对应的EventContext。得到的是EventContext类型的派生类RTSPListenerSocket。相应的代码在EventContext.cpp中的249到253行。
- 调用ProcessEvent,处理事件。相应的代码在EventContext.cpp中的257行。注意,由于对应的EventContext类其实是RTSPListenerSocket,因此调用的应该是TCPListenerSocket::ProcessEvent。
- 在TCPListenerSocket.cpp的106行TCPListenerSocket::ProcessEvent方法中,调用accept得到socket,在160行调用了GetSessionTask方法,对应的是RTSPListenerSocket::GetSessionTask,在QTSServer.cpp中定义。
- 在RTSPListenerSocket::GetSessionTask方法中,QTSServer.cpp的1077行,调用NEW RTSPSession建立了一个新的RTSPSession。
- 回到TCPListenerSocket.cpp文件中的TCPListenerSocket::ProcessEvent方法,注意189行,把刚刚建立好的RTSP连接加入到侦听队列,等待RTSP请求的到来。
RTSP请求的处理流程步骤如下,注意前面第一步是一样的:
- RTSP连接请求到达后,被select_waitevent函数捕获,代码在EventContext.cpp的EventThread::Entry中232行。
- 查找EventThread::fRefTable,获取对应的EventContext。得到的是EventContext类。相应的代码在EventContext.cpp中的249到253行。
- 调用ProcessEvent,处理事件。相应的代码在EventContext.cpp中的257行。注意,此时调用的是EventContext::ProcessEvent。
- EventContext::ProcessEvent方法在EventContext.h中实现,在127行。在138行调用了fTask->Signal(Task::kReadEvent),fTask就是RTSPSession类。把RTSPSession加入到TaskThread的队列等待RTSPSession::Run()被调用。
- 后续就是RTSPSession::Run()对RTSP请求的具体的处理。
- linux下面的aio(2011-10-27 14:33:22)
- 编写Darwin的Module来支持新的流媒体文件格式(2011-02-15 21:35:30)
- libev入门(2011-01-09 15:21:10)
- Darwin中RTSP协议的实现(2010-12-31 21:24:44)
- Darwin中QTSS调用的文件访问部分的实现(草稿)(2010-12-28 23:47:32)
- Dictionary数据类型在Darwin视频服务器中的使用(草稿)(2010-12-19 15:11:04)
- 高性能IO设计模式及其应用(2010-12-18 21:40:30)
Darwin Streaming Server 核心代码分析的更多相关文章
- 【转】Darwin Streaming Server 核心代码分析
无意中看到了dqzhangp的一篇博客,分析了DSS的核心架构,读完顿时感觉豁然开朗,茅塞顿开,写得非常的鞭辟入里,言简意赅,我想没有相当的功力是写不出这样的文章的,情不自禁转到自己空间来,生怕弄丢了 ...
- Darwin Streaming Server 简介
Darwin Streaming Server 概要 Darwin Streaming Server简称DSS.DSS是Apple公司提供的开源实时流媒体播放服务器程序.整个程序使用C++编写 ...
- Darwin Streaming server 的 Task 类
Darwin Streaming Server 是一个开放源代码的streaming server,对于streaming server的编程和软件结构有着一定的参考价值,它是使用C++写的,其中的并 ...
- Darwin Streaming Server用vs2005编译运行过程
原创. 一:编译 Darwin6.0.3版本是最新版本,也提供了.dsw文件.但是使用vs2005和vc6是编译不过的.所以,采用Darwin5.5.5版本.使用vc6打开WinNTSupport文件 ...
- Darwin Streaming Server Relay Setting
安装完Darwin Streaming Server,就可以使用VLC通过RTSP协议播放流媒体文件了.但是我现在有一个需求,需要将一台DSS(假设为A机)上的媒体文件发送到另一台DSS(假设为B机) ...
- Darwin Streaming Server 6.0.3安装、订制、插件或模块
How to setup Darwin Streaming Server 6.0.3 on 32 or 64 bit Linux platforms, add custom functionality ...
- Darwin Streaming Server 安裝操作備忘
Darwin Streaming Server 安裝操作 Darwin Streaming Server是蘋果公司推出的開放源碼.跨平台多媒體串流伺服器, 提供音樂 (mp3) 與影音 (3gp.mp ...
- Linux编译安装Darwin Streaming Server 6.0.3。。。
目前主流的流媒体服务器有微软的windows media server.RealNetworks的Helixserver和苹果公司的Darwin Streaming Server. 微软的window ...
- Linux编译安装Darwin Streaming Server 6.0.3
买回来VPS后就一直想在上面搭建一个流媒体服务,在网上搜索了很多资料,大部分都是介绍Linux中安装Darwin Streaming Server 5.5.5版本,因为这个版本提供了针对linux的安 ...
随机推荐
- 使用css绘制六边形
用css绘制六边形需要使用到三个容器,分别用于绘制六边形的三个部分,如下图所示: 接下来,就是代码了: CSS: ;;border-top: 30px solid #6c6;border-left: ...
- 2018.11.7 PION 模拟赛
期望:100 + 80 + 75 = 255 实际:0 + 80 + 60 = 140 唉~一天比一天犯的错误智障,感觉noip要凉啊... 吓得我赶紧吃几颗药补补脑子. 奶一下大佬: lgj AK ...
- InnoDB: The Auto-extending innodb_system data file './ibdata1' is of a different size 640 pages (rounded down to MB) than specified in the .cnf file: initial 768 pages, max 0 (relevant if non-zero) pa
2016-09-14T09:17:37.713955Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleane ...
- windows redis 服务安装坑
环境 winserver 2012 最新版的redis:3.0.503 redis-server.exe --service-install redis.windows.conf --m ...
- 【Todo】【读书笔记】Linux高性能服务器编程
在读 /Users/baidu/Documents/Data/Interview/服务器-检索端/<Linux高性能服务器编程.pdf> 其实之前读过,要面试了,需要温习. P260 So ...
- firebug console说明
控制台(Console)是Firebug的第一个面板,也是最重要的面板,主要作用是显示网页加载过程中产生各类信息. 一.显示信息的命令 Firebug内置一个console对象,提供5种方法,用来显示 ...
- zedboard中OLED源码
#include <stdio.h> #include "platform.h" #include "xil_types.h" #include & ...
- Androidproject文件下assets目录与res目录的差别
1. assets : 不会在R.java文件下生成对应的标记,assets目录能够自己创建目录,必须使用AssetsManager类进行訪问,存放到这里的资源在执行打包的时候都会打入程序安装包中, ...
- Linux fcntl函数详解
功能描述:根据文件描述词来操作文件的特性. 文件控制函数 fcntl -- file control 头文件: #include <unistd.h> #include ...
- Canvas坐标轴中的Y轴距离是X轴的两倍
如题,相信很多人在初次玩canvas的时候会出现这样的情况,跟着教程走的情况下,诶 怎么画出来的东西,不怎么对劲啊,,,ԾㅂԾ,,!!!!!先上代码 <!DOCTYPE html> < ...