webrtc 多線程五 physicalsocketserver

physicalsocketserver

webrtc/base/physicalsocketserver.h /physicalsocketserver.cc 文件實現(xiàn)了一個基本的多路信號分離器吵取。這個多路信號分離器的實現(xiàn)代碼可以橫跨 Windows日缨、Linux、OSX玉控、Android灶挟、ios 等平臺坏逢,非常復雜。其實在 /base 目錄下妙黍,還有多個 SocketServer 的實現(xiàn)悴侵,從這些 SocketServer 的名字就可以看出是針對哪些平臺特化實現(xiàn),比如MacCocoaSocketServer废境。在這里我就不對這些 SocketServer 進行分析畜挨,只要能夠明白 PhysicalSocketServer 的原理,再加上對平臺API的了解應(yīng)該很容易讀懂這些平臺特化的 SocketServer噩凹。

在該文件中將大量使用 socket 相關(guān)的系統(tǒng)調(diào)用巴元。由于本篇章的內(nèi)容為多線程編程,所以盡量不做過多的涉及驮宴,并且忽略引用其他文件定義的 socket 相關(guān)類(比如 PhysicalSocket )逮刨。

Dispatcher

該類定義了事件分發(fā)器的純虛基類。事件分發(fā)器主要是將 IO 或 Event 信號對應(yīng)到一定的處理函數(shù)上去堵泽。該純虛基類在 Windows 和 Posix2 個平臺下定義的函數(shù)接口有很大的區(qū)別修己。但是主要的功能大致差不多。

PhysicalSocket

該類是 physicalsocketserver.cc 文件的內(nèi)部私有的類迎罗,不對外暴露睬愤,它主要是對 Socket 的跨平臺封裝。由于 Windows 也提供了基本和 BSDsocket 一致的 Socket API 所以該類的代碼不難理解纹安。

PhysicalSocket 的主要組件包括:

  • s_:socket句柄/文件描述符

  • enabled_events_:需要監(jiān)聽的IO事件

  • udp_:通信方式是否為UDP

  • error_:最后出錯碼(Last Error)

  • state_:連接狀態(tài)

  • resolver_:異步的網(wǎng)址解析器

PhysicalSocket 的主要成員函數(shù)包括:


構(gòu)造函數(shù):創(chuàng)建并初始化PhysicalSocket對象

參數(shù)說明:

ss:管理的SocketServer
s:封裝的系統(tǒng)socket句柄/文件描述符尤辱;如果不提供該參數(shù), PhysicalSocket 將創(chuàng)建一個厢岂;如果提供 PhysicalSocket 將對其進行封裝

PhysicalSocket::Create:創(chuàng)建系統(tǒng) socket 句柄/文件描述符

參數(shù)說明:

family:socket的尋址方案(AF_INET/AF_INET6)光督;從這個參數(shù)可以看出 WebRTC 是支持IPV6的
type:socket的類型(TCP/UDP)

PhysicalSocket::Connect:連接指定的地址和端口,如果地址尚未解析塔粒,調(diào)用異步的地址解析器

參數(shù)說明:

addr:需要連接的地址(使用 SocketAddress结借,該類包括地址和端口號)
 

PhysicalSocket::EstimateMTU:獲取socket連接的MTU(最大傳輸單元)

參數(shù)說明:

mtu:返回最大傳輸單元
返回值:出錯碼
原理:

Windows 平臺調(diào)用 Ping 庫獲取

IOS 和 OSX 平臺沒有簡單地方法獲取,直接返回出錯

Linux 平臺調(diào)用 getsockopt(s_,IPPROTO_IP, IP_MTU, &value, &vlen)獲取

由于 Windows 提供了基本和 BSD socket一致的 API卒茬,所以在 Windows 的代碼和 Linux 的代碼幾乎一致船老。一下將簡單對比一下 API:

socket咖熟、getsocketname、getpeername努隙、bind球恤、connect、recv荸镊、recvfrom咽斧、accept、closesocket

Linux 平臺下完全一致

getsockopt躬存、setsockopt

Linux 平臺下完全一致(僅有一些特殊的選項不同)

send张惹、sendto

在 Linux 平臺下將最后一個參數(shù) flag 設(shè)置為 MSG_NOSIGNAL,屏蔽 SIGPIPE

PhysicalSocket 需要注意 2 點:

  1. 雖然它繼承自 AsyncSocket岭洲,但是它管理的內(nèi)部系統(tǒng) socket 句柄/描述符是阻塞的(它的子類 SocketDispatcher 會將系統(tǒng) socket 句柄/描述符轉(zhuǎn)為非阻塞的)宛逗。繼承自 AsyncSocket 的原因可能是為了避免多繼承造成類繼承結(jié)構(gòu)過于復雜。

  2. 雖然該類具有很多和 SocketServer 相關(guān)的成員變量和成員函數(shù)盾剩,但是 PhysicalSocketServer 不能直接管理PhysicalSocket雷激。能被 PhysicalSocketServer 管理的是 PhysicalSocket 的一個子類 SocketDispatcher,它也是一個 physicalsocketserver.cc 內(nèi)部私有的一個類告私。

當然以上這 2 點只是實現(xiàn)的細節(jié)問題屎暇,這些類都是不對外暴露的,我們僅僅需要懂得如何使用對外暴露的接口就可以了驻粟。

EventDispatcher

EventDispatcher 類實現(xiàn)了跨平臺的等價于 Win32 自動重置( autoreset )WSAEvent 的功能根悼。在 Windows 平臺上有網(wǎng)絡(luò)多線程開發(fā)經(jīng)驗的讀者應(yīng)該很熟悉 WSAEvent,我就不再多做介紹了蜀撑。

之前講解過 Event 類挤巡。那 PhysicalSocketServer 還需要 EventDispatcher 來模擬 Event 呢?這是因為 Event 僅僅實現(xiàn)了 Win32 的 WaitForSingleObject 函數(shù)的功能酷麦,這無法應(yīng)用到多路信號分離器里面去矿卑。多路信號分離器需要有能力在一個阻塞函數(shù)里等待多個 event 和 IO 信號的能力,在 Windows 平臺上就是W SAWaitForMultipleEvents 函數(shù)的功能沃饶。

與之相類似的在 Linux 平臺上可以使用的 API 有 select 函數(shù)粪摘,不過 select 函數(shù)只能等待 IO 信號不能等待其他 Event。這就很難實現(xiàn)一個阻塞函數(shù)同時等待 IO 信號和消息隊列的功能绍坝。這對于網(wǎng)絡(luò)服務(wù)器端的開發(fā)并不是非常重要,但是對于圖形用戶界面客戶端的開發(fā)沒有這個功能有時會變得很麻煩苔悦。而 EventDispatcher 的職責就是為我們模擬出這個功能轩褐。

既然 select 函數(shù)已經(jīng)具有了我們需要的一半功能,怎樣才能獲得另一半功能呢玖详?比較直接的方法就是將一個 event 的 signal 語義轉(zhuǎn)化為 IO 信號把介,是的 WebRTC 就是這么做的勤讽。linux 版本的 EventDispatcher 的一個成員變量是一對管道( pipe )的文件描述符。如果需要 signal 一個 EventDispatcher拗踢,只要對這個管道發(fā)送一個字節(jié)(內(nèi)容無所謂)脚牍,就能打開 select 函數(shù)的阻塞狀態(tài)。緊接著 EventDispatcher 會立即將管道內(nèi)的數(shù)據(jù)讀出巢墅,EventDispatcher 重新回到unsignal 的狀態(tài)诸狭。這就實現(xiàn)了 event 的 auto reset 語義。當然君纫,這種實現(xiàn)并不完美驯遇,比如說多個 select 等待在同一個EventDispatcher 上就會出問題。WebRTC 的開發(fā)人員也明白這一點蓄髓,所以對 EventDispatcher 加上了以下注釋:

[cpp] view plain copy
// It is not possible to perfectly emulate an auto-resetting event with  
// pipes.  This simulates it byresetting before the event is handled.  

雖然存在以上的問題叉庐,但這并不影響 EventDispatcher 配合 PhysicalSocketServer 的工作。因為每一個EventDispatcher 實例僅隸屬于一個 PhysicalSocketServer会喝,所以不存在多個 PhysicalSocketServer 等待同一個EventDispatcher 的狀況陡叠。這也可能是為什么 EventDispatcher 是 physicalsocketserver.cc 文件私有的原因。

通過上面的講解我們應(yīng)該可以理解 Linux 版的 EventDispatcher 的工作原理肢执。以下我將 Windows 版本和 Linux 版本的API 調(diào)用做一下簡單類比:

WSACreateEvent

pipe函數(shù)枉阵,用于創(chuàng)建管道

WSACloseEvent

close函數(shù),用于關(guān)閉管道

WSASetEvent

write函數(shù)蔚万,向管道內(nèi)寫入一個字節(jié)數(shù)據(jù)岭妖,用以解鎖阻塞的 select 函數(shù)

WSAResetEvent

read 函數(shù),從管道內(nèi)讀出所有數(shù)據(jù)反璃,清除管道的可讀狀態(tài)昵慌,下次調(diào)用 select 函數(shù)時恢復阻塞

PosixSignalHandler

PosixSignalHandler 和 PosixSignalDispatcher 這兩個類只有 Linux 版本。并且在整個 WebRTC 的源代碼中沒有任何地方使用過這兩個類淮蜈。因此斋攀,對它們的代碼分析主要是為了幫助 Windows 開發(fā)人員從實用的角度學習如何使用 linux 平臺下的部件。

PosixSignalHandler 類主要實現(xiàn)了將 Linux 的 Signal 機制納入到多路分離器的架構(gòu)中去梧田。對于 Windows 開發(fā)人員來說淳蔼,Signal 機制是一個比較陌生的東西。而且對它的處理比較麻煩裁眯。因為 Signal 會在程序運行的任何時候出現(xiàn)鹉梨,一旦觸發(fā)就會調(diào)用注冊的處理函數(shù),開發(fā)人員沒法假定這時程序中哪些工具是否可用穿稳。正如在PosixSignalHandler::OnPosixSignalReceived 函數(shù)的注釋中所說的在出錯的時候我們甚至無法記錄log:

[cpp] view plain copy
// Nothing we can do here. If there's an error somehow then there's  
// nothing we can safely do from a signal handler.  
// No, we can't even safely log it.  

此外存皂,Linux 的有些 signal 相關(guān)的函數(shù)在不同版本的 Linux/Unix 平臺以及的表現(xiàn)完全不同。因為,signal 機制是一個古老的歷史遺留問題旦袋,在當年 Unix 主導一切骤菠,各個大公司又各自為戰(zhàn)的年代,要提供一個公認完備的標準確實不易疤孕。幸運的是從WebRTC 的代碼來看商乎,幾乎沒有什么組件使用了 signal 機制,那就說明絕大多數(shù)的現(xiàn)代程序都是可以不使用 signal 機制就能實現(xiàn)自己想要的功能的祭阀。

首先鹉戚,讓我們來看一下 PosixSignalHandler 類的工作原理。它被偽裝成了一個 singleton柬讨,而它其實是一個全局唯一的對象崩瓤,創(chuàng)建后永不釋放,直到程序退出時內(nèi)存泄露踩官。注意却桶,這不是開發(fā)人員不小心泄露了內(nèi)存,而是主動的泄露了內(nèi)存蔗牡。在 WebRTC 中有一個專用的宏( LIBJINGLE_DEFINE_STATIC_LOCAL )用來定義定義這種類實例颖系。如果,在程序中有限的幾個類實例被設(shè)置成 LIBJINGLE_DEFINE_STATIC_LOCAL 理論上來說是沒有什么負面效果的辩越。因為它不會造成程序在運行期間不斷地積累內(nèi)存泄露直到拖垮整個系統(tǒng)嘁扼。

但是使用這種手法依然需要謹慎。在使用 PosixSignalHandler 的時候黔攒,PhysicalSocketServer 會將 PosixSignalHandler::OnPosixSignalReceived 函數(shù)通過 sigaction 注冊到系統(tǒng)以響應(yīng)感興趣 signal趁啸。當系統(tǒng)發(fā)出被監(jiān)聽的 signal 后 OnPosixSignalReceived 函數(shù)會被調(diào)用。該函數(shù)會在成員變量 received_signal_(數(shù)組)中相應(yīng)的位置上設(shè)置為 true督惰,并在 pipe 中寫入 1 個字節(jié)的數(shù)據(jù)(是的不傅,它的核心工作原理和 EventDispatcher 是一樣的),這樣就能解鎖阻塞等待在 select 函數(shù)上的 PhysicalSocketServer赏胚。PhysicalSocketServer 通過PosixSignalHandler::IsSignalSet 函數(shù)來檢查 received_signal_ 數(shù)組以確定哪個 signal 被激活访娶,并調(diào)用相應(yīng)的處理函數(shù)。

在PosixSignalHandler中主要使用的Linux API包括:

  • pipe:創(chuàng)建管道

  • fcntl:設(shè)置文件描述符的選項觉阅;該函數(shù)在構(gòu)造函數(shù)中被調(diào)用崖疤,將新創(chuàng)建的一對pipe文件描述符設(shè)置為非阻塞。調(diào)用代碼為:fcntl(afd_[0], F_SETFL, O_NONBLOCK)典勇。不過劫哼,根據(jù)EventDispatcher構(gòu)造函數(shù)的代碼來看,這一步好像沒有必要割笙÷儋耍考慮到EventDispatcher是一個被重度使用的對象,可以確信沒有必要把pipe的文件描述符設(shè)置為非阻塞(pipe默認應(yīng)該就是阻塞的,并且在絕大多數(shù)系統(tǒng)中IO默認都是阻塞的)豪嚎。

  • read:從管道讀出數(shù)據(jù),解除管道文件描述符的可讀狀態(tài)(該函數(shù)在PosixSignalDispatcher中使用)

  • write:向管道寫入數(shù)據(jù)谈火,以解鎖阻塞的select函數(shù)

  • close:關(guān)閉管道

  • sigaction:將signal處理函數(shù)注冊到系統(tǒng)侈询,當signum指定編號的signal觸發(fā)時,系統(tǒng)會調(diào)用相應(yīng)的處理函數(shù)(該函數(shù)在PhysicalSocketServer::InstallSignal中使用)

PosixSignalDispatcher

該類也是 Linux 獨有的一個類糯耍,主要是作為代表 PosixSignalHandler 的分發(fā)器扔字,通過將該對象添加入PhysicalSocketServer 可以將實現(xiàn)接收 PosixSignal。它的原理已經(jīng)在上一節(jié) PosixSignalHandler 中討論過了温技,這里就不再多做分析革为。它的主要函數(shù)如下:

PosixSignalDispatcher::SetHandler:將signal的響應(yīng)函數(shù)加入到分發(fā)器

參數(shù)說明:

signum:需要響應(yīng)的signal編號
handler:當signal觸發(fā)時,響應(yīng)的處理函數(shù)

SocketDispatcher

SocketDispatcher 類主要將 PhysicalSocket 封裝成一個分發(fā)器舵鳞。所以震檩,在實現(xiàn)上該類僅僅就是為 PhysicalSocket 添加一些 Dispatcher 接口需要的一些成員函數(shù),以及一些狀態(tài)維護代碼蜓堕。僅有在 Linux 版本僅有的成員函數(shù)SocketDispatcher::IsDescriptorClosed 中有些比較特殊的情況抛虏。通過這個函數(shù)中的注釋我們發(fā)現(xiàn)尚無一些可靠的手段判斷一個 socket 文件描述符是否已經(jīng)被關(guān)閉,所以實現(xiàn)代碼使用了 ::recv(s_, &ch, 1, MSG_PEEK) 來判斷套才。在 Window 版本的 SocketDispatcher 中沒有這個成員函數(shù)迂猴。除此之外,SocketDispatcher 類的 Windows 實現(xiàn)和 Linux 實現(xiàn)基本一致背伴。以下對比一下 2 個平臺 API 調(diào)用的情況:

  • ioctlsocket

  • fcntl函數(shù)用于設(shè)置文件描述符的選項(比如阻塞或非阻塞)

FileDispatcher

FileDispatcher 類是一個 Linux 平臺獨有的類沸毁,它的功能是簡單將文件描述符封裝成 Dispatcher。不過它在 WebRTC 中基本上沒有使用過傻寂。該類在創(chuàng)建的時候(構(gòu)造函數(shù)中)抽碌,接受并保存文件描述符,并通過 fcntl 函數(shù)將文件描述符設(shè)置為非阻塞荚孵。此外它還實現(xiàn)了一些 Dispatcher 接口要求的一些函數(shù)较剃,并維護一些狀態(tài)變量。該類并沒有什么難點个绍。

Signaler

Signaler 的用處只有一個:實現(xiàn) PhysicalSocketServer 的 signal_wakeup_ 成員變量(用于解除多路信號分離器的阻塞狀態(tài))勒葱。它的主要功能由父類 EventDispatcher 實現(xiàn),僅僅添加了在解除多路信號分離器阻塞狀態(tài)后將PhysicalSocketServer::fwait_ 成員變量設(shè)置為 false 的代碼巴柿。PhysicalSocketServer::fwait_ 成員變量在被設(shè)置為 false 后凛虽,PhysicalSocketServer::Wait 函數(shù)就會退出,MessageQueue 就可以及時處理消息隊列的消息广恢。

PhysicalSocketServer

如果說 MessageQueue 是多路信號分離器的外圍凯旋,那么 PhysicalSocketServer 就是多路信號分離器的真正核心。PhysicalSocketServer 主要實現(xiàn)了消息和 IO 的多路分發(fā)功能,類似于 Windows 平臺上的 WSAWaitForMultipleEvents 的功能至非。

PhysicalSocketServer 的主要成員變量包括:

  • dispatchers_:分發(fā)器列表

  • signal_wakeup_:中止 PhysicalSocketServer::Wait 函數(shù)的 Signaler 對象(通常在 MessageQueue 接收到事件時調(diào)用)

PhysicalSocketServer 的主要成員函數(shù)包括:

PhysicalSocketServer::CreateSocket:創(chuàng)建一個Socket實例钠署,實質(zhì)為PhysicalSocket

參數(shù)說明:

family:socket 的尋址方案(AF_INET/AF_INET6),說明 WebRTC 能夠支持 IPv6
type:socket 的類型(TCP/IP)

 

PhysicalSocketServer::CreateAsyncSocket:創(chuàng)建一個AsyncSocket實例荒椭,實質(zhì)是SocketDispatcher谐鼎。此外,與PhysicalSocketServer::CreateSocket函數(shù)不同的是創(chuàng)建后的實例立即被添加入PhysicalSocketServer的分發(fā)器列表(dispatchers_)趣惠。用戶不需要在調(diào)用PhysicalSocketServer::Add函數(shù)

參數(shù)說明:

family:socket的尋址方案(AF_INET/AF_INET6)狸棍,說明WebRTC能夠支持IPv6
type:socket的類型(TCP/IP)


PhysicalSocketServer::WrapSocket:將一個系統(tǒng)socket句柄/文件描述符封裝成SocketDispatcher并添加入分發(fā)器列表(PhysicalSocketServer::dispatchers_)

參數(shù)說明:

s:一個系統(tǒng)socket句柄/文件描述符,可以是同步(阻塞)的味悄,也可以是異步(非阻塞)的草戈。如果是同步的,該函數(shù)會通過fcntl(Linux)或ioctlsocket(Windows)轉(zhuǎn)成異步的侍瑟。


PhysicalSocketServer::Add/Remove:向分發(fā)器列表添加/刪除一個分發(fā)器

參數(shù)說明:

pdispatcher:一個添加/刪除的Dispatcher實例唐片,PhysicalSocketServer在下一次IO監(jiān)聽循環(huán)中會添加/刪除監(jiān)聽它的句柄/文件描述符。注意丢习,是下一次監(jiān)聽循環(huán)牵触,新添加的分發(fā)器不會影響當前阻塞的select(linux)函數(shù)或WSAWaitForMultipleEvents(Windows)函數(shù)。也不會喚醒當前阻塞的select(Linux)函數(shù)或WSAWaitForMultipleEvents(Windows)函數(shù)咐低。如果開發(fā)人員需要添加/刪除操作立即生效揽思,需要自行喚醒當前阻塞的select(Linux)函數(shù)或WSAWaitForMultipleEvents(Windows)函數(shù)。


PhysicalSocketServer::Wait:實現(xiàn)了多路信號分離器

參數(shù)說明:

cmsWait:以毫秒為單位的等待時間见擦,kForever表示永久等待
process_io:是否處理IO

PhysicalSocketServer 的核心代碼就在成員函數(shù) Wait 中钉汗。該函數(shù)比較復雜我將分幾個要點來講解:

大體流程

在 PhysicalSocketServer::Wait 函數(shù)中,代碼的主體為 IO 監(jiān)聽循環(huán)鲤屡。在 IO 監(jiān)聽循環(huán)中损痰,Wait 函數(shù)首先將分發(fā)器列表( PhysicalSocketServer::dispatchers_ )中所有分發(fā)器的 IO 句柄/文件描述符加入到監(jiān)聽數(shù)組(需要注意的是分發(fā)器列表已經(jīng)包括了 PhysicalSocketServer::signal_wakeup_,激發(fā)該分發(fā)器可以終止整個 IO 監(jiān)聽循環(huán)酒来,導致 Wait 函數(shù)退出)卢未。接著 Wait 函數(shù)就調(diào)用系統(tǒng)的 IO 阻塞等待函數(shù),在 Linux 平臺上為 select堰汉,在 Windows 平臺上為 WSAWaitForMultipleEvents辽社。

Wait 函數(shù)阻塞等待 IO 期間釋放 CPU 資源。在阻塞等待 API 返回時翘鸭,Wait 函數(shù)先檢查它的返回值滴铅。如果是因為等待超時,Wait 函數(shù)將立即返回就乓。否則汉匙,將調(diào)用被激發(fā) IO 句柄/文件描述符的分發(fā)器的 OnPreEvent 和 OnEvent 函數(shù)拱烁。最后,檢查 PhysicalSocketServer::fwait_噩翠,如果需要繼續(xù)等待就再次執(zhí)行 IO 監(jiān)聽循環(huán)戏自,否則就退出 Wait 函數(shù)。整個函數(shù)流程如下圖所示:

阻塞等待機制(Windows)

雖然 PhysicalSocketServer::Wait 函數(shù)在 Windows 平臺和 Linux 平臺上的流程大體相同绎秒,但是在實現(xiàn)細節(jié)上卻有很大不同浦妄。首先讓我們先看一下 Windows 平臺。Windows 平臺調(diào)用的等待 API 是 WSAWaitForMultipleEvents见芹,該函數(shù)有能力將多個 IO 句柄使用 WSAEventSelect 函數(shù)綁定到一個 WSAEvent 句柄上去,并在等待結(jié)束后調(diào)用 WSAEnumNetworkEvents 來確定到底哪些 IO 句柄被激發(fā)蠢涝。

所以玄呛, Windows 版本的 Dispatcher 定義有兩個成員函數(shù) GetSocket 和 GetWSAEvent。如果能調(diào)用 GetSocket 函數(shù)返回一個有效的 socket和二,那么就將這個 socket 句柄綁定到一個統(tǒng)一的 WSAEvent 上徘铝;如果不能返回一個有效的 socket 句柄就繼續(xù)調(diào)用 GetWSAEvent,取出分發(fā)器的 WSAEvent惯吕,并把它加入到 WSAWaitForMultipleEvents 函數(shù)的等待數(shù)組中去惕它。大致過程如下圖所示:

阻塞等待機制(Linux)

Linux 的 PhysicalSocketServer::Wait 相對來說比較簡單。它使用 select 函數(shù)等待所有從Dispatcher::GetDescriptor 返回的文件描述符废登。所有的文件描述符一視同仁淹魄,也沒有內(nèi)置特殊文件描述符。select 函數(shù)返回后調(diào)用相應(yīng)的 Dispatcher 的事件響應(yīng)函數(shù) OnPreEvent 和 OnEvent堡距。唯一比較復雜的就是 PhysicalSocketServer::signal_dispatcher_甲锡,具體的原理見 PosixSignalHandler。

與 MessageQueue 互動

其實羽戒,這部分內(nèi)容已經(jīng)在前面的章節(jié)講述過一些了缤沦,只是比較分散。在這里我將比較全面總結(jié)一下:

  • 整個多路信號分離器由 MessageQueue 和 PhysicalSocketServer 組成易稠,這 2 個組件輪流獲得控制權(quán)缸废。 MessageQueue 最先獲得控制權(quán),它會檢查自己的消息隊列驶社,如果有需要立即處理的消息就馬上處理企量,如果沒有就把控制權(quán)交給 PhysicalSocketServer。PhysicalSocketServer 將等待所有位于其分發(fā)器列表(PhysicalSocketServer::dispatchers_)的 IO 句柄/文件描述符衬吆。如果有 IO 句柄/文件描述符被激發(fā)梁钾,PhysicalSocketServer 將調(diào)用對應(yīng)的 Dispatcher 的消息響應(yīng)函數(shù)(OnPreEvent、OnEvent)逊抡。

  • 如果在 PhysicalSocketServer 阻塞等待時 MessageQueue 接收到消息姆泻,MessageQueue 將會調(diào)用PhysicalSocketServer::WakeUp 函數(shù)激發(fā) PhysicalSocketServer::signal_wakeup_ 以解除PhysicalSocketServer 的阻塞狀態(tài)零酪。并將 PhysicalSocketServer::fWait_ 設(shè)置為false,這將導致PhysicalSocketServer 退出 IO 監(jiān)控循環(huán)重新將控制權(quán)交給 MessageQueue拇勃。MessageQueue 獲得控制權(quán)后將立即處理消息四苇,在完成消息處理后再將控制權(quán)交給 PhysicalSocketServer。

由于方咆,PhysicalSocketServer 的實現(xiàn)比較復雜月腋,因此已經(jīng)無法比較 Windows 平臺和 Linux 平臺的代碼。所以瓣赂,僅僅簡單羅列一下Linux平臺下的API:

  • select:用于對IO文件描述符數(shù)組進行輪詢榆骚,阻塞等待IO信號

  • FD_ZERO:用于初始化一個IO文件描述符數(shù)組的宏

  • FD_SET:用于將IO文件描述符添加入由FD_ZERO初始化的IO文件描述符數(shù)組的宏

  • FD_ISSET:用于檢查一個IO文件描述符數(shù)組是否包括指定的IO文件描述符。由于select函數(shù)在返回時會將沒有激發(fā)的IO文件描述符剔除掉煌集,所以依然存在于數(shù)組中的IO文件描述符表示已經(jīng)被激發(fā)

  • FD_CLR:從IO文件描述符數(shù)組中刪除一個指定的IO文件描述符

到此妓肢,我們已經(jīng)完成了對整個多路信號分離器的分析。但是苫纤,這還不是 WebRTC 線程模型的全部碉钠,它還有一個重要的模塊——thread,之后將對它進行分析卷拘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喊废,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子栗弟,更是在濱河造成了極大的恐慌污筷,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件横腿,死亡現(xiàn)場離奇詭異颓屑,居然都是意外死亡,警方通過查閱死者的電腦和手機耿焊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門揪惦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人罗侯,你說我怎么就攤上這事器腋。” “怎么了钩杰?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵纫塌,是天一觀的道長。 經(jīng)常有香客問我讲弄,道長措左,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任避除,我火速辦了婚禮怎披,結(jié)果婚禮上胸嘁,老公的妹妹穿的比我還像新娘。我一直安慰自己凉逛,他們只是感情好性宏,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著状飞,像睡著了一般毫胜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诬辈,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天酵使,我揣著相機與錄音,去河邊找鬼焙糟。 笑死凝化,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的酬荞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼瞧哟,長吁一口氣:“原來是場噩夢啊……” “哼混巧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勤揩,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤咧党,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后陨亡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體傍衡,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年负蠕,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛙埂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡遮糖,死狀恐怖绣的,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欲账,我是刑警寧澤屡江,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站赛不,受9級特大地震影響惩嘉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踢故,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一文黎、第九天 我趴在偏房一處隱蔽的房頂上張望惹苗。 院中可真熱鬧,春花似錦臊诊、人聲如沸鸽粉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽触机。三九已至,卻和暖如春玷或,著一層夾襖步出監(jiān)牢的瞬間儡首,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工偏友, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔬胯,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓位他,卻偏偏與公主長得像氛濒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鹅髓,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容