基本概念
首先,我針對的代碼是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:
html
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鏈接請求的過程:
socket
RTSP鏈接請求到達後,被select_waitevent函數捕獲,代碼在EventContext.cpp的EventThread::Entry中232行。函數
查找EventThread::fRefTable,獲取對應的EventContext。獲得的是EventContext類型的派生類RTSPListenerSocket。相應的代碼在EventContext.cpp中的249到253行。this
調用ProcessEvent,處理事件。相應的代碼在EventContext.cpp中的257行。注意,因爲對應的EventContext類實際上是RTSPListenerSocket,所以調用的應該是TCPListenerSocket::ProcessEvent。url
在TCPListenerSocket.cpp的106行TCPListenerSocket::ProcessEvent方法中,調用accept獲得socket,在160行調用了GetSessionTask方法,對應的是RTSPListenerSocket::GetSessionTask,在QTSServer.cpp中定義。spa
在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請求的具體的處理。