版本說(shuō)明
本文分析基于2019-12-30的版本稚配。(Live555沒(méi)有版本管理?)
1 Hash容器
1.1 HashTable
HashTable 定義了Hash表的接口淆攻。
- 成員函數(shù) Add()、Remove() 和 Lookup() 分別用于添加、刪除和查找元素臭猜。
1.2 HashTable
BasicHashTable實(shí)現(xiàn)了HashTable接口。這是hash表的一個(gè)標(biāo)準(zhǔn)實(shí)現(xiàn)押蚤。
- 成員fBuckets[]指向一個(gè)TableEntry*的數(shù)組蔑歌。其中每個(gè)元素指向一個(gè)TableEntry鏈表。TableEntry包括一個(gè)(key揽碘,value)對(duì)次屠。
- 成員函數(shù) hashIndexFromKey()計(jì)算key的HASH值。它將Key值進(jìn)行若干變換雳刺,然后限縮在數(shù)組fBuckets的索引范圍內(nèi)劫灶。
- 成員函數(shù)keyMatches()用于比較兩個(gè)key值是否相同。
- insertNewEntry()向Hash表添加新元素掖桦。
- 它調(diào)用hashIndexFromKey()計(jì)算在數(shù)組fBucket中的索引浑此,然后創(chuàng)建新的TableEntry實(shí)例,并掛接到該索引位置上的TableEntry鏈表滞详。
- TableEntry的key值一般有兩種類(lèi)型:string和unsigned凛俱。兩種類(lèi)型計(jì)算HASH值的方法不同紊馏。
- 如果Hash表中的TableEntry實(shí)例數(shù)超過(guò)指定的閾值,則調(diào)用rebuild()重建Hash表蒲犬,將成員fBuckets[]加長(zhǎng)朱监。這樣做的目的是保證Hash表的效率。
2 任務(wù)調(diào)度
2.1 TaskScheduler
TaskScheduler定義任務(wù)調(diào)度器接口原叮。
TaskScheduler接口涵蓋三種任務(wù):Socket監(jiān)聽(tīng)赫编、延時(shí)任務(wù)、和事件通知任務(wù)奋隶。后面依次說(shuō)明這三種任務(wù)擂送。
- 成員函數(shù)setBackgroundHandling()創(chuàng)建Socket監(jiān)聽(tīng)任務(wù)。
- 成員函數(shù)createEventTrigger()創(chuàng)建事件通知任務(wù)唯欣,triggerEvent()觸發(fā)任務(wù)嘹吨。
- 成員函數(shù)scheduleDelayedTask()創(chuàng)建延時(shí)任務(wù)。
- 成員函數(shù)doEventLoop()處理任務(wù)境氢。
2.2 HandlerDescritor蟀拷、HandlerSet - Socket監(jiān)聽(tīng)任務(wù)
HandlerDescriptor保存socket、以及與socket關(guān)聯(lián)的處理函數(shù)萍聊。
- 成員socketNum是socket的值
- 成員conditionSet是fd_set值的組合
- handlerProc是指定的處理函數(shù)问芬,clientData是handlerProc的參數(shù)。
這些成員分別指定應(yīng)該監(jiān)控Socket上的什么事件(可讀寿桨、可寫(xiě)此衅、異常),事件發(fā)生時(shí)應(yīng)該調(diào)用什么函數(shù)處理它亭螟。
HandlerSet是HandlerDescriptor的集合挡鞍。
如下圖,HandlerSet的成員fHandlers保存一個(gè)HandlerDescriptor雙向列表媒佣。
對(duì)于HandlerDescriptor匕累,
- 成員fPrevHandler和fNextHandler用于鏈接雙向鏈表陵刹。
對(duì)于HandlerSet默伍,
- 成員函數(shù)assignHandler()設(shè)置Socket的處理函數(shù)。創(chuàng)建新的HandlerDescriptor實(shí)例衰琐,或者更新已有的實(shí)例也糊。創(chuàng)建HandlerDescriptor實(shí)例時(shí),將它鏈接在雙向鏈表的尾部羡宙。
- 成員函數(shù)clearHandler()清除Socket的處理函數(shù)狸剃。在HandlerDescriptor的析構(gòu)函數(shù)中,把它自身從雙向鏈表中移除狗热。
- 成員函數(shù)lookupHandler()查找Socket的處理函數(shù)钞馁。
HanderIterator基于HandlerDescriptor雙向鏈表虑省。
- 調(diào)用它的成員函數(shù)next(),可以遍歷HandlerDescriptor鏈表僧凰。
2.3 AlarmHandler - 延時(shí)任務(wù)
DelayQueueEntry保存延時(shí)任務(wù)探颈,而DelayQueue保存一個(gè)DelayQueueEntry雙向鏈表。
對(duì)于DelayQueueEntry训措,
- 成員fDeltaTimeRemaining保存延時(shí)的時(shí)長(zhǎng)伪节,這是一個(gè)相對(duì)值。
- 成員fPrev和fNext 讓DelayQueueEntry的多個(gè)實(shí)例能鏈成一個(gè)雙向列表绩鸣。
- 虛擬成員函數(shù)handleTimeout()是延時(shí)到達(dá)時(shí)執(zhí)行的函數(shù)怀大。DelayQueueEntry的派生類(lèi)可以定制自己的實(shí)現(xiàn)。
DelayQueue是一個(gè)DelayQueueEntry容器呀闻。
- 它從DelayQueueEntry派生化借。這樣的設(shè)計(jì)看起來(lái)只是為了不需要為起始節(jié)點(diǎn)加一個(gè)DelayQueryEntry成員。(讓人迷惑的設(shè)計(jì)W苤椤)
- 成員函數(shù)addEntry()屏鳍、updateEntry()、和removeEntry()分別用于增加局服、更新和移除元素钓瞭。
AlarmHandler是DelayQueueEntry的派生類(lèi),實(shí)現(xiàn)了虛擬成員函數(shù)handleTimeout()淫奔。
- 成員fProc是處理函數(shù)山涡,由handleTimeout()調(diào)用。成員fClientData是fProc的參數(shù)唆迁。兩者在AlarmHandler的構(gòu)造函數(shù)中作為參數(shù)指定鸭丛。
在DelayQueueEntry雙向鏈表中,元素的延時(shí)fDeltaTimeRemaining是相對(duì)的唐责,是前一個(gè)元素的相對(duì)值鳞溉。
如下圖中,有4個(gè)元素鼠哥,它們的fDeltaTimeRemaining值分別是4熟菲、4、3和2朴恳,那么第一個(gè)元素的實(shí)際延時(shí)是最近的抄罕,是4,其他元素的實(shí)際延時(shí)依次累加于颖,分別是8呆贿、11和13。
DelayQueueEntry和DelayQueue用Timeval度量時(shí)間森渐。Timeval的派生類(lèi)DelayInterval和_EventTime做入,是對(duì)Timeval的簡(jiǎn)單包裝冒晰。
2.4 事件通知任務(wù)
沒(méi)有定義專(zhuān)門(mén)的類(lèi)處理事件通知任務(wù)。BasicTaskScheduler0類(lèi)直接處理這類(lèi)任務(wù)竟块。
2.5 BasicTaskScheduler0旧巾、BasicTaskScheduler
BasicTaskSchduler0實(shí)現(xiàn)了TaskScheduler接口箭窜,實(shí)現(xiàn)延時(shí)任務(wù)和事件監(jiān)聽(tīng)任務(wù)芹橡。
BasicTaskScheduler派生自BasicTaskScheduler0打厘,進(jìn)一步實(shí)現(xiàn)socket監(jiān)聽(tīng)任務(wù)。
對(duì)于BasicTaskSchduler0秫逝,
- 實(shí)現(xiàn)shceduleDelayedTask()創(chuàng)建延時(shí)任務(wù)恕出。成員fDelayQueue保存一組延時(shí)任務(wù)。
- 實(shí)現(xiàn)createEventTrigger()和triggerEvent()违帆,創(chuàng)建浙巫、觸發(fā)事件通知任務(wù)。成員fTriggerEventHandlers[]保存一組事件通知任務(wù)刷后。
- BasicTaskScheduler0定義了新接口的畴,也就是新的虛擬函數(shù)SingleStep()。它實(shí)現(xiàn)了虛擬函數(shù)doEventLoop()尝胆。在里面丧裁,它在循環(huán)中調(diào)用singleStep()。
對(duì)于BasicTaskScheduler含衔,
- 實(shí)現(xiàn)setBackgroundHandling()創(chuàng)建Socket監(jiān)聽(tīng)任務(wù)煎娇。BasicTaskScheduler0的成員fHandlers保存socket處理函數(shù)。(為什么不是BasicTaskSchduler的成員贪染?)
- 實(shí)現(xiàn)BasicTaskScheduler0定義的接口SingleStep()缓呛。
在BasicTaskScheduler::SingleStep()中,
- 調(diào)用select()杭隙,監(jiān)聽(tīng)HandlerSet中保存的socket的可讀哟绊、可寫(xiě)和異常信號(hào)。如果有信號(hào)痰憎,則調(diào)用指定HandlerSet實(shí)例中指定的處理函數(shù)TaskScheduler::BackgroundHandleProc()處理票髓。
- 檢查fTriggerEventHandlers[]中的任務(wù)是否為觸發(fā)狀態(tài),如果是信殊,則調(diào)用指定處理函數(shù)TaskFunc()進(jìn)行處理炬称。
- 調(diào)用DelayQueue::handleAlarm()汁果,檢查成員fDelayQueue中延時(shí)任務(wù)是否到達(dá)涡拘,如果是,調(diào)用處理函數(shù)TaskFunc()進(jìn)行處理据德。
3 程序上下文
3.1 UsageEnvironment
UsageEnvironment定義了一個(gè)輸出打印消息的接口鳄乏。
- 成員函數(shù)setResultMsg()將打印消息保存起來(lái)跷车,getResultMsg()獲得保存的打印信息, reportBackgroundError()輸出保存的打印信息橱野。
- operator <<() 一系列成員函數(shù)朽缴,輸出指定格式的數(shù)據(jù)。
BasicUsageEnvironment0實(shí)現(xiàn)了這個(gè)接口的setResultMsg()水援、getResultMsg()和reportBackgroundError()密强。
- 成員fResultMsgBuffer[]保存打印消息。
- reportBackgroundError()向stderr輸出打印消息蜗元。
BasicUsageEnvironment進(jìn)一步實(shí)現(xiàn)了這個(gè)接口的operator<<()系列函數(shù)或渤。
- 這些函數(shù)向stderr輸出打印消息。
UsageEnvironment還是整個(gè)程序運(yùn)行的上下文奕扣。
- 成員fScheduler引用全局唯一的TaskScheduler實(shí)例
- 成員liveMediaPriv引用全局唯一的_Tables實(shí)例薪鹦,保存了兩個(gè)全局表。
- 成員groupsockPriv實(shí)際上是_groupsockPriv實(shí)例惯豆,保存幾個(gè)組播全局變量池磁,其中reuseFlag是綁定Socket時(shí)是否重用地址。
應(yīng)用程序只創(chuàng)建一個(gè)UsageEnvironment實(shí)例楷兽。
3.2 _Tables - 全局容器
_Tables保存幾個(gè)hash表地熄。
- _Tables是singleton模式,調(diào)用getOurTables()可以得到唯一的實(shí)例芯杀。
- 成員mediaTable是其中一個(gè)Hash表离斩,它是MediumLookupTable的實(shí)例。
3.3 Medium瘪匿、MediaLookupTable
Medium給它的派生類(lèi)的實(shí)例保存一個(gè)名字跛梗。
- 成員fMediumName[]保存這個(gè)名字。這個(gè)名字調(diào)用MediaLookupTable::generateNewName()得到棋弥。
- Medium還引用唯一的UsageEnvironment實(shí)例核偿。
MediumLookupTable保存一個(gè)Medium集合。這個(gè)集合保存在成員fTable中顽染,這是一個(gè)HashTable實(shí)例漾岳。
- addNew()、lookup()和remove()分別向hashtable加入粉寞、查找和刪除Medium實(shí)例尼荆。