mac TeamTalk開發(fā)點(diǎn)點(diǎn)滴滴之一——DDLogic框架分解 - 刀哥的技術(shù)隨筆

由于TT原班人馬離職,文章丟失涣达,暫留備份

轉(zhuǎn)載地址

mac TeamTalk開發(fā)點(diǎn)點(diǎn)滴滴之一——DDLogic框架分解上 - 刀哥的技術(shù)隨筆

mac TeamTalk開發(fā)點(diǎn)點(diǎn)滴滴之一——DDLogic框架分解下 - 刀哥的技術(shù)隨筆

DDLogic框架著重解決如下這幾個(gè)點(diǎn):

  • 1.基于Task的任務(wù)調(diào)度
  • 2.事件的訂閱與發(fā)布
  • 3.pdu通信協(xié)議以及拆裝包過程
  • 4.基于WSAAsyncSelect模型的網(wǎng)絡(luò)異步I/O TCP/IP長(zhǎng)連接
  • 5.業(yè)務(wù)模塊拆分以及模塊與模塊之間通過接口交互
  • 6.持久化數(shù)據(jù)以及基于此數(shù)據(jù)之上的一層數(shù)據(jù)監(jiān)聽機(jī)制(類似IDE工具調(diào)試的 Watch)

下面針對(duì)每個(gè)點(diǎn)分別做描述:

1 基于Task的任務(wù)調(diào)度(Task 調(diào)度)

任何應(yīng)用程序都會(huì)存在一個(gè)個(gè)需要處理的業(yè)務(wù),只有如此你的應(yīng)用程序才是活的,才能完成用戶的業(yè)務(wù)需求悠轩。這些任務(wù)或是后臺(tái)計(jì)算性、或是網(wǎng)絡(luò)通信的拆包/裝包攻泼、又或是前端交互的如動(dòng)畫計(jì)算火架,可以說整個(gè)應(yīng)用程序就是由這樣的一個(gè)個(gè)task跑起來的。那么如何來合理的調(diào)度這些任務(wù)呢忙菠?之前寫過的一篇《TT和chrome線程模型對(duì)比分析》何鸡,同學(xué)們可以去看下,這里把任務(wù)調(diào)度相關(guān)的文字直接挪過來下牛欢。
一圖勝千言骡男,先上下DDLogic的執(zhí)行邏輯模型圖如下:

ddlogic_1.jpg

這張圖告訴我們幾點(diǎn):

  • 1.TT是多線程的,線程分為UI主線程傍睹、網(wǎng)絡(luò)異步I/O線程隔盛、邏輯任務(wù)執(zhí)行器線程池犹菱、http線程池等
1.1 主線程(UI線程):負(fù)責(zé)界面的顯示和交互,以及借助消息循環(huán)來做事件的派發(fā).

1.2 網(wǎng)絡(luò)異步I/O線程:負(fù)責(zé)TCP/IP長(zhǎng)連接以及消息服務(wù)器數(shù)據(jù)包的收發(fā).

1.3 邏輯任務(wù)執(zhí)行器線程池:一個(gè)簡(jiǎn)單的可伸縮的任務(wù)執(zhí)行池吮炕,F(xiàn)IFO task list thread線程執(zhí)行一些正常任務(wù)腊脱, Priority queue thread可以執(zhí)行一些優(yōu)先級(jí)調(diào)度或者dependency調(diào)度,Priority queue thread也可以在某個(gè)重任務(wù)把常駐線程耗掉的時(shí)候龙亲,開啟一個(gè)新線程來執(zhí)行后續(xù)饑渴任務(wù)陕凹。

 1.4 http線程池:由于除主線程外所有子線程都沒有MessagePump,邏輯任務(wù)執(zhí)行器線程池只能負(fù)責(zé)一些后臺(tái)計(jì)算性的任務(wù)(因?yàn)槿绻谶壿媹?zhí)行器里面執(zhí)行http任務(wù)俱笛,有可能會(huì)被同步http請(qǐng)求,卡住導(dǎo)致后續(xù)的任務(wù)不能夠得到及時(shí)響應(yīng))传趾,所以只能再做個(gè)http線程池來專門處理http相關(guān)的任務(wù).
 
  • 2.任務(wù)執(zhí)行單位——Task
2.1 task的創(chuàng)建和執(zhí)行是分開的(command模式)迎膜,可以在任何的線程中創(chuàng)建一個(gè)task,然后通過調(diào)用TaskPool的pushTask將任務(wù)放到TaskPool的線程池中執(zhí)行浆兰。

2.2 整個(gè)過程只有在pushTask的時(shí)候才加鎖磕仅,等到開始執(zhí)行的時(shí)候是無鎖的,所以在設(shè)計(jì)task的時(shí)候簸呈,開發(fā)者需要考慮到task中的數(shù)據(jù)對(duì)象管轄的范圍榕订。

2.3 task執(zhí)行過程中產(chǎn)生的事件通知都是利用主線程的消息循環(huán)dispatch出去的(這一點(diǎn)與chrome有很大的不同)

這塊接下來的目標(biāo)會(huì)盡量和chrome的思想靠齊,特別是在線程任務(wù)的設(shè)計(jì)上chrome允許創(chuàng)建的每個(gè)線程都有執(zhí)行各種任務(wù)的能力蜕便,并且也為之創(chuàng)建了各種的任務(wù)執(zhí)行隊(duì)列來異步執(zhí)行劫恒,這樣的輪子便于整個(gè)項(xiàng)目功能和業(yè)務(wù)的分解。
Task調(diào)度的實(shí)現(xiàn)代碼分析將放到《mac TeamTalk開發(fā)點(diǎn)點(diǎn)滴滴之四——NSOperation與Task》做深入的闡述轿腺,敬請(qǐng)期待两嘴。

2 事件的訂閱與發(fā)布 (Event Watch機(jī)制)

在一個(gè)框架里面有一套統(tǒng)一的、方便使用的事件訂閱與發(fā)布是非常有必要的族壳°颈瑁看過一些優(yōu)秀的開源代碼、框架都有各自的不同程度不同方式的實(shí)現(xiàn)仿荆,如libevent的event-driven贰您,一個(gè)高性能的服務(wù)器網(wǎng)絡(luò)庫(kù);如.net framework 委托與事件拢操;如delphi(object pascal) VCL的回調(diào)函數(shù)指針與事件等锦亦,同學(xué)們可以自行去研究下,特別是libevent的實(shí)現(xiàn)值得一看令境。DDLogic對(duì)于這塊的設(shè)計(jì)需要達(dá)到這樣的效果——即觀察者可以通過監(jiān)聽某個(gè)業(yè)務(wù)模塊的某個(gè)唯一屬性(MKN=module key name)的變化孽亲,當(dāng)該屬性發(fā)生變化的時(shí)候,觀察者能夠及時(shí)的獲得同步或者異步方式的處理展父。基于此目的mac TT和windows TT分別用不同的技術(shù)達(dá)到了DDLogic的設(shè)計(jì)需求返劲。

**mac TT **

mac TT依托于強(qiáng)大的OC運(yùn)行時(shí)庫(kù)支持動(dòng)態(tài)創(chuàng)建類玲昧、c語言原始的函數(shù)指針、函數(shù)調(diào)用在運(yùn)行時(shí)才去做二進(jìn)制重定位即編譯時(shí)調(diào)用者不需要確保被調(diào)用函數(shù)的存在篮绿,實(shí)現(xiàn)Event機(jī)制的方式可以多種多樣孵延,我知道的有協(xié)議與委托、類別與委托亲配、C語言的函數(shù)指針與回調(diào)尘应、target/action、鍵值觀察(KVO)吼虎、RunRoop(和windows的消息循環(huán)差不多)犬钢,還有NS庫(kù)提供的NotificationCenter等。PS:同學(xué)們可以去膜拜下《深入淺出Cocoa》( 深入淺出Cocoa)思灰。

首先玷犹,先看下DDLogic Event Watch機(jī)制的使用好有個(gè)初步感受,描述如下:
  • 1 首先將眾多事件根據(jù)業(yè)務(wù)模塊(module)來拆分洒疚,如會(huì)話module里面定義的事件屬性包括:
//module key names 
static NSString* const MKN_DDSESSIONMODULE_GROUPMSG = @"DDSESSIONMODULE_GROUPMSG";          //群消息到達(dá)

static NSString* const MKN_DDSESSIONMODULE_SINGLEMSG = @"DDSESSIONMODULE_SGINGLEMSG";       //個(gè)人息到達(dá)
  • 2 需要監(jiān)聽事件的地方調(diào)用如下歹颓,實(shí)現(xiàn)
[[DDLogic instance] addObserver:MODULE_ID_SESSION name: MKN_DDSESSIONMODULE_SINGLEMSG observer:self selector:@selector(onHandleSingleMsg:)];

onHandleSingleMsg函數(shù),即具體的事件處理函數(shù)油湖。
  • 3 在群信息/個(gè)人信息到達(dá)的時(shí)候發(fā)布事件巍扛,調(diào)用如下發(fā)布通知
[self uiAsyncNotify:MKN_DDSESSIONMODULE_SINGLEMSG userInfo:userInfo];

咋樣上面使用起來很簡(jiǎn)單吧,典型的觀察者模式接口設(shè)計(jì)乏德。再完善一點(diǎn)可以像.net framework撤奸、Delphi VCL可視化訂閱事件一樣,將事件源的定義和事件和事件處理函數(shù)的綁定集成到xcode上去喊括。

接下來講講DDLogic Event Watch機(jī)制在mac上是如何實(shí)現(xiàn)的寂呛。

DDLogic是借助了上文描述的NS庫(kù)提供的NSNotificationCenter來實(shí)現(xiàn),其實(shí)和NSNotificationCenter原生態(tài)的使用沒啥區(qū)別瘾晃,所以有些同學(xué)會(huì)問了NSNotificationCenter 接口使用文檔贷痪。我這里想著重回答下同學(xué)們的一個(gè)疑問:因?yàn)榭隙ㄓ袝?huì)有同學(xué)問,本身NSNotificationCenter就已經(jīng)很好用了而且你的框架也是簡(jiǎn)單包裝了下而已蹦误,為啥要這樣做呢劫拢?這里我的解釋也不想套用啥高大上的理論,我自己的理解是:

  • 1 DDLogic去包裝NSNotificationCenter主要目的是定制一套統(tǒng)一的規(guī)則即定義module key
    name强胰、監(jiān)聽module key name的事件通知與處理舱沧、以及統(tǒng)一的事件發(fā)布。

  • 2 對(duì)于框架的層面不應(yīng)該與某種技術(shù)選型耦合太深偶洋,就拿NSNotificationCenter技術(shù)選型來講熟吏,當(dāng)未來的某一天這套通知機(jī)制不夠用的時(shí)候,可以方便的替換掉選擇更適合的技術(shù)選型,這個(gè)時(shí)候可以盡量把替換封裝在框架內(nèi)而不用因此去重構(gòu)業(yè)務(wù)層代碼牵寺。

  • 3 在技術(shù)選型上做一層適配悍引,其實(shí)還有個(gè)好處是可以對(duì)你的技術(shù)選型做一個(gè)定制,比如你選擇了NSNotificationCenter技術(shù)帽氓,但是發(fā)現(xiàn)NSNotificationCenter庫(kù)很強(qiáng)大支持各種場(chǎng)景趣斤,但是你的項(xiàng)目其實(shí)不需要那么重巴碗,通過適配是可以降低使用者對(duì)NSNotificationCenter的學(xué)習(xí)成本当辐。

  • 4 還有一點(diǎn)是開發(fā)mac TT DDLogic的時(shí)候据德,windows TT的框架已經(jīng)成型了宇智,為了保持一致的使用體驗(yàn),我就特地去包裝了下买乃,寬恕我吧_

**windows TT **

windows平臺(tái)由于沒有類似NSNotificationCenter這樣的優(yōu)秀的平臺(tái)庫(kù)歹茶,不可避免對(duì)于DDLogic Event Watch機(jī)制的封裝需要自己去造輪子泊碑,當(dāng)然會(huì)麻煩許多工作量也上升了一個(gè)指數(shù)捎拯。使用方式和上面寫的差不多泪幌,這里就不重復(fù)寫了,大家可以去看下具體的源碼玄渗。
接下來講講DDLogic Event Watch機(jī)制在windows上是具體實(shí)現(xiàn)座菠。它借助了

  1. 一層三元組[module_id,module_item,module_tag]來組成一個(gè)數(shù)據(jù)集(DataSet也可以稱作Document)狸眼。
  2. fastDelegate(一套開源的用c++實(shí)現(xiàn)的委托藤树,比成員函數(shù)指針回調(diào)效率更高,有興趣的可以自己去研究下(http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible))實(shí)現(xiàn)函數(shù)回調(diào)即調(diào)用到具體的事件處理函數(shù)拓萌。
  3. 操作系統(tǒng)的消息循環(huán)岁钓,包裝成事件通知。
    一圖勝千言如下圖:
ddlogic_2.png

通過圖示具體實(shí)現(xiàn)如下:

  1. 創(chuàng)建一個(gè)無窗口的句柄用來作為異步事件派發(fā)的基礎(chǔ)微王,即底層最終是借助windows操作系統(tǒng)的消息循環(huán)來封裝上層的Event事件的派發(fā)的屡限,支持同步/異步派發(fā)(即SendMessage/PostMessage)。
  2. 生成一個(gè)全局唯一的三元組 DataSet實(shí)例用來存儲(chǔ)各個(gè)業(yè)務(wù)模塊觀察者關(guān)心的唯一屬性炕倘,類似mac TT的MKN(module key
    name)钧大,存儲(chǔ)格式按照三元組[module_id,module_item,module_tag],module_id對(duì)應(yīng)業(yè)務(wù)模塊ID罩旋,module_item對(duì)應(yīng)登陸者信息啊央,module_tag則對(duì)應(yīng)MKN。
    3.在需要監(jiān)聽事件的地方調(diào)用
    logic::GetLogic()->addWatch(this
    ,MAKE_DELEGATE(this,&SessionChat::OnEvaluateWatch,serv::DID_EVALUTATE_CONFIG)
    OnEvaluateWatch函數(shù)涨醋,即具體的事件處理函數(shù)瓜饥。
    4.在發(fā)布事件的地方調(diào)用
    logic::GetLogic()->asyncPostEvent(serv::DID_EVALUTATE_CONFIG
    ,module_item,TAG_EVALUTATE_CONFIG,pData);

3 PDU通信協(xié)議以及拆裝包過程

(協(xié)議數(shù)據(jù)單元(Protocol Data Unit))PDU通信協(xié)議走的是二進(jìn)制協(xié)議——即固定長(zhǎng)度的協(xié)議頭(16個(gè)字節(jié)) + 協(xié)議體方式。協(xié)議頭包括整個(gè)協(xié)議包的大小浴骂、版本乓土、模塊號(hào)(moduleid)、命令號(hào)(commandid)等。模塊號(hào)(moduleid)和業(yè)務(wù)模塊對(duì)應(yīng)趣苏,commandid對(duì)應(yīng)具體的網(wǎng)絡(luò)傳輸命令狡相,這樣做的好處是通過包頭就可以知道這個(gè)包是屬于那個(gè)業(yè)務(wù)模塊處理的。對(duì)于協(xié)議這塊的技術(shù)選型拦键,我們當(dāng)時(shí)也討論了許多谣光,我、大子騰芬为、大子燁分別都提出了各自的解決方案萄金,最終選擇了大子騰的PDU協(xié)議,這個(gè)過程考慮的因素很多媚朦,所以我準(zhǔn)備專門寫一篇blog來分寫下當(dāng)時(shí)的情景氧敢,另外這篇博文還會(huì)分析PDU通信協(xié)議和chrome的對(duì)比,敬請(qǐng)期待...這里就不再深入描述了询张。

接下來講下協(xié)議的拆包/裝包與DDLogic的分層吧孙乖,雖然和具體通信協(xié)議交集不是那么大,但是想想還是放這里比較適份氧。
如圖:

ddlogic_3.png

從這幅圖可以簡(jiǎn)單看出:

1.協(xié)議層:協(xié)議的拆包和協(xié)議任務(wù)的分配都封裝在協(xié)議層唯袄,對(duì)業(yè)務(wù)層是透明的
2.協(xié)議層:協(xié)議拆包完成后,會(huì)生成一個(gè)task放入任務(wù)執(zhí)行池蜗帜,做任務(wù)派發(fā)的工作
3.業(yè)務(wù)層:根據(jù)module_id會(huì)分派到相應(yīng)的業(yè)務(wù)模塊
4.業(yè)務(wù)層:收到通知后恋拷,根據(jù)協(xié)議里面的command_id處理具體業(yè)務(wù)

4 TCP/IP長(zhǎng)連接

大部分客戶端應(yīng)用程序的網(wǎng)絡(luò)I/O模型采用阻塞模式就夠用了,如遇到UI和網(wǎng)絡(luò)需要異步厅缺,很常用的一種實(shí)現(xiàn)方式是啟用多線程將網(wǎng)絡(luò)數(shù)據(jù)的收發(fā)放到工作者線程中去蔬顾。但是對(duì)網(wǎng)于IM這種應(yīng)用場(chǎng)景來說阻塞模式就不適用了,試想聊天過程中你和服務(wù)器之間的交互是多么的頻繁湘捎,你可以同時(shí)和幾十位用戶一起聊天诀豁,為了不阻塞難道每次聊天收發(fā)信息都需要建立一個(gè)線程來實(shí)現(xiàn)嗎?這當(dāng)然是不現(xiàn)實(shí)的窥妇,所以我們需要選擇非阻塞模式異步socket IO舷胜。下面分別講講mac pro 和 windows的網(wǎng)絡(luò)異步I/O的實(shí)現(xiàn)。

mac TT

mac TT得益于oc提供的良好平臺(tái)目前借助的是CFNetwork和NSStream類實(shí)現(xiàn)TCP/IP 異步I/O socket活翩,利用CFNetwork創(chuàng)建socket通信通道烹骨,利用NSStream傳遞單向的數(shù)據(jù)流,具體實(shí)現(xiàn)如下: 通過在NSStream中增加一個(gè)類方法擴(kuò)展用于建立TCP/IP連接的一系列過程纱新。

+ (void)getStreamsToHostNamed:(NSString *)hostName port:(NSInteger)port inputStream:(NSInputStream **)inputStream outputStream:(NSOutputStream **)outputStream
{
  CFHostRef        host;

  CFReadStreamRef    readStream;

  CFWriteStreamRef  writeStream;

  host = CFHostCreateWithName(NULL, (__bridge CFStringRef) hostName);

  CFStreamCreatePairWithSocketToCFHost(NULL, host, (SInt32)port, &readStream, &writeStream);

  CFRelease(host);

  ...
}

NSStream的兩個(gè)派生類NSInputStream/NSOutputStream把整個(gè)socket通信抽象成了一個(gè)輸入/輸出流展氓,通過oc平臺(tái)的RunLoop將異步I/O事件通知到如下回調(diào)函數(shù)中:

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
   switch(eventCode) {
      ...
   }
}

回調(diào)通知的事件有:

typedef NS_OPTIONS(NSUInteger, NSStreamEvent) {

  NSStreamEventNone = 0,

  NSStreamEventOpenCompleted = 1UL << 0, //輸入or輸出流打開成功即socket連接建立成

  NSStreamEventHasBytesAvailable = 1UL << 1, //可以接受數(shù)據(jù)通知即輸入緩沖區(qū)有內(nèi)容了

  NSStreamEventHasSpaceAvailable = 1UL << 2, //可以發(fā)送數(shù)據(jù)通知即輸出緩沖區(qū)空了

  NSStreamEventErrorOccurred = 1UL << 3, //錯(cuò)誤通知

  NSStreamEventEndEncountered = 1UL << 4

};
   以上具體代碼可以參見mac tt代碼NSStream+NStreamAddtion.m 以及 MGJMTalkClient.m(現(xiàn)在換成DDTcpClientManager.m)

咋樣整個(gè)過程看下來是不都看不到socket的影子?這樣做有啥好處呢脸爱?我自己的理解最大的好處是足夠簡(jiǎn)單遇汞,對(duì)于調(diào)用者來說socket的整個(gè)過程是透明的,調(diào)用者不需要去理解操作系統(tǒng)對(duì)異步socket的I/O模型的支持,不需要去理解socket建立的整個(gè)過程等埋凯。類似的還有java的NIO甚至netty庫(kù)都把整個(gè)socket過程隱藏在了一個(gè)流的概念中甩恼。 盡說好處了,差點(diǎn)忘記目前DDLogic的這種實(shí)現(xiàn)還有一個(gè)很大的問題(PS:是不是我們使用上有問題,同學(xué)們也可以幫忙看下)小压,即connet TCP服務(wù)器的時(shí)候烤咧,回調(diào)事件里面腫么也收不到連接斷失敗的事件通知昌阿,導(dǎo)致整個(gè)TCP/IP流程不流暢笋颤,我們暫時(shí)采用了一個(gè)很齷齪的方式是:connet TCP服務(wù)器的時(shí)候設(shè)置個(gè)定時(shí)器,如果3秒鐘沒有收到連接建立成功的通知就認(rèn)為連接失敗了阱缓。這里的代碼我擔(dān)心也會(huì)為將來開發(fā)IOS TT埋下一個(gè)隱患秉版,建議IOS開發(fā)同學(xué)去深入研究下或者尋找更好的技術(shù)選型。這里提供幾個(gè)參考

  1. OC平臺(tái)OS層的基于C的 BSD socket茬祷,這一層面提供的是socket原生態(tài)的方法清焕,可以最大程度的控制網(wǎng)絡(luò)編程,但是工作量也是最大的祭犯,和windows TT采用C/C++ 進(jìn)行socket編程差不多秸妥。
  2. OC平臺(tái)Core Foundation層提供的CFNetwork C ,對(duì)OS層的BSD socket做了一層簡(jiǎn)單的包裝沃粗,并且和系統(tǒng)的run loop結(jié)合起來粥惧,使得異步socket I/O實(shí)現(xiàn)起來很方便。上面mac TT用的其實(shí)就是這一層最盅,所以這里還是需要去深入研究上面的坑突雪。
  3. OC平臺(tái)最上層提供的Bonjour庫(kù),同學(xué)們可以自行去看下 Networking and Bonjour on iPhone
  4. 另辟蹊徑不走OC平臺(tái)提供的庫(kù)涡贱,用libevent來實(shí)現(xiàn)咏删,不過對(duì)于客戶端來說使用該庫(kù)可能略重,但是它良好的封裝使得使用起來非常簡(jiǎn)單而且本身也是輕量級(jí)高性能的網(wǎng)絡(luò)庫(kù)问词,客戶端選擇POSIX select或windows select模型足夠用了督函。

windows TT

windows TT是基于windows的WSAAsyncSelect模型建立的異步I/O,利用這個(gè)模型應(yīng)用程序可在一個(gè)套接字上激挪,接收以Windows消息為基礎(chǔ)的網(wǎng)絡(luò)事件通知辰狡,對(duì)于一個(gè)客戶端程序已經(jīng)足夠用了。code projct有個(gè)對(duì)該模型很好的包裝垄分,同學(xué)們可以去看下( http://www.codeproject.com/Articles/3855/CAsyncSocketEx-Replacement-for-CAsyncSocket-with-p )宛篇。具體的實(shí)現(xiàn)windows并沒有像oc平臺(tái)這樣好的抽象,但是實(shí)現(xiàn)起來其似乎也是差不多的思想薄湿,異步I/O消息通知的事件包括:FD_READ叫倍、FD_WRITE豌鸡、FD_FORCEREAD、FD_CONNECT段标、FD_ACCEPT涯冠、FD_CLOSE這些,每個(gè)事件都相應(yīng)的能通知到socket數(shù)據(jù)處理層就可以了逼庞。

比較下來兩個(gè)系統(tǒng)平臺(tái)對(duì)于TCP/IP異步socket IO的封裝是差不多的蛇更,差別只是抽象的層次mac pro平臺(tái)更加高一點(diǎn),windows更加接近原生態(tài)的socket赛糟。 以上講的是利用各自平臺(tái)的網(wǎng)絡(luò)庫(kù)實(shí)現(xiàn)與服務(wù)器之間通信的技術(shù).

接下來一起看下在內(nèi)存中收發(fā)數(shù)據(jù)的兩個(gè)buffer派任,因?yàn)閿?shù)據(jù)傳遞是異步的,發(fā)送/接收數(shù)據(jù)都有可能是還沒有真正發(fā)送/接收成功璧南,所以需要在socket數(shù)據(jù)處理層維護(hù)兩塊buffer——inBuffer(接收數(shù)據(jù)緩存)/outBuffer(發(fā)送數(shù)據(jù)緩存)掌逛。以outBuffer(發(fā)送數(shù)據(jù)緩存)為例子,當(dāng)你調(diào)用sendSocketData的時(shí)候司倚,由于操作系統(tǒng)發(fā)送緩存區(qū)滿了導(dǎo)致調(diào)用失敗 豆混,由于是異步socket IO,系統(tǒng)的send過程并不會(huì)等待系統(tǒng)的發(fā)送緩存區(qū)空了再發(fā)送數(shù)據(jù)动知,而是會(huì)讓send過程失敗皿伺,等到系統(tǒng)的發(fā)送緩存區(qū)空的時(shí)候通過一個(gè)可寫的事件通知你,所以在sendSocketData過程send失敗的情況下盒粮,你所需要做的就是將數(shù)據(jù)緩存到outBuffer(發(fā)送數(shù)據(jù)緩存)中鸵鸥,等到可寫事件收到了再將outBuffer(發(fā)送數(shù)據(jù)緩存)的數(shù)據(jù)發(fā)送出去,上個(gè)流程圖吧:

ddlogic_4.png

5 業(yè)務(wù)模塊拆分以及模塊與模塊之間通過接口交互

任何應(yīng)用程序從業(yè)務(wù)角度講都不是單一的丹皱,是由許多業(yè)務(wù)組裝起來的(比如mac TT有登陸業(yè)務(wù)妒穴、文件傳輸業(yè)務(wù)、消息管理業(yè)務(wù)摊崭、會(huì)話管理業(yè)務(wù)等)讼油,那么這些業(yè)務(wù)需要如何有機(jī)的結(jié)合起來完成一個(gè)應(yīng)用程序的所有需求呢?同學(xué)們應(yīng)該會(huì)首先想到MVC(Model爽室、View汁讼、Controller)/MVP(Model淆攻、View阔墩、Presenter),嗯沒錯(cuò),在OC平臺(tái)中本身就是按照MVC來實(shí)現(xiàn)具體業(yè)務(wù)的開發(fā)的瓶珊,DDLogic在MVC基礎(chǔ)之上再加了一個(gè)Module的概念啸箫,為的是和前面:基于Task的任務(wù)調(diào)度、pdu通信協(xié)議以及拆裝包過程伞芹、事件的訂閱與發(fā)布忘苛、持久化數(shù)據(jù)以及基于此數(shù)據(jù)之上的一層數(shù)據(jù)監(jiān)聽機(jī)制(類似IDE工具調(diào)試的 Watch)這些有機(jī)的結(jié)合起來蝉娜,回頭看看是否還記得前面PDU協(xié)議面的module id和存儲(chǔ)格式按照三元里面的module id呢?先上個(gè)簡(jiǎn)單的圖吧:

ddlogic_5.png

DDLogic的思路是這樣的(以登陸業(yè)務(wù)模塊為例子):

// 現(xiàn)在的好像是DDLoginManager.m
 1.所有模塊的對(duì)外接口都通過DDLogic Modules Manager來管理扎唾。
 2.模塊與模塊之間通過接口來調(diào)用召川,
模塊內(nèi)部實(shí)現(xiàn)對(duì)外不可見。比如外部只能調(diào)用DDloginModule的doLogin()來實(shí)現(xiàn)登陸操作胸遇,調(diào)用方是不知道具體如何實(shí)現(xiàn)登陸的荧呐。
 3.每個(gè)獨(dú)立的業(yè)務(wù)創(chuàng)建成為業(yè)務(wù)module——DDLoginModule,有一個(gè)全局唯一的業(yè)務(wù)模塊ID——MODULE_ID_LOGIN
 4.調(diào)用業(yè)務(wù)模塊的接口函數(shù)通過全局唯一業(yè)務(wù)模塊ID——MODULE_ID_LOGIN來纸镊,DDLoginModule*
loginModule = getDDModule(MODULE_ID_LOGIN);[loginModule doLogin];
 5.支持插件管理倍阐,n(n >=1)個(gè)模塊合作來組裝成1個(gè)插件,并且支持動(dòng)態(tài)加載/卸載(未實(shí)現(xiàn)的目標(biāo))

是不感覺DDLogic框架連這種東西也拿出來分享逗威,沒啥技術(shù)含量是個(gè)程序員都知道用類似的方式來拆分業(yè)務(wù)峰搪?是的你的感覺是對(duì)的,但是只對(duì)了一半凯旭,確實(shí)看起來沒啥營(yíng)養(yǎng)概耻,但是請(qǐng)你再往下看你會(huì)發(fā)覺這個(gè)點(diǎn)才是整個(gè)DDLigic框架的精髓,如果說上面講的每個(gè)設(shè)計(jì)點(diǎn)是DDLogic框架的一條條河流的話罐呼,那么這里就應(yīng)該是它們的匯聚地咐蚯,下面逐個(gè)點(diǎn)來分析

 1.基于Task的任務(wù)調(diào)度:每個(gè)task的執(zhí)行都會(huì)綁定一個(gè)module_id來知道具體是哪個(gè)模塊的task在執(zhí)行,并且通過module_id將任務(wù)執(zhí)行的結(jié)果反饋給模塊弄贿,這條河流就匯聚到module了春锋。
 2.事件的訂閱與發(fā)布:每個(gè)事件都是通過指定module_id和MKN來訂閱的,等到被訂閱事件發(fā)布的時(shí)候同樣通過指定module_id和MKN來通知出去差凹,這條河流也匯聚到moudule了
 3.pdu通信協(xié)議以及拆裝包過程:通過解析pdu協(xié)議頭獲取module_id和command_id期奔,然后生成NetworkTask派發(fā)到相應(yīng)的模塊中區(qū),這條河流也匯聚到module了
 4.持久化數(shù)據(jù)以及基于此數(shù)據(jù)之上的一層數(shù)據(jù)監(jiān)聽機(jī)制(類似IDE工具調(diào)試的 Watch):通過儲(chǔ)格式三元組[module_id,module_item,module_tag]危尿,這條河流也匯聚到module了

6 持久化存儲(chǔ)以及基于此數(shù)據(jù)模型數(shù)據(jù)監(jiān)聽機(jī)制(類似IDE調(diào)試工具的Watch)

DDLogic數(shù)據(jù)持久化用的是NSCoder可以支持基于業(yè)務(wù)模塊的數(shù)據(jù)序列化/反序列化呐萌。基于數(shù)據(jù)模型的監(jiān)聽機(jī)制(暫且稱作data watch機(jī)制)對(duì)一個(gè)應(yīng)用程序來說是非常實(shí)用的,舉個(gè)例子:你的好友管理模塊的數(shù)據(jù)新增了一個(gè)好友谊娇,好友列表數(shù)據(jù)發(fā)生add事件肺孤,監(jiān)聽此數(shù)據(jù)變化的模塊如好友列表控件、消息管理模塊等都會(huì)收到相應(yīng)的通知并作出及時(shí)的處理济欢。

這塊將放到《

mac TT開發(fā)點(diǎn)點(diǎn)滴滴之四——NSCode與DDlogic的結(jié)合》中做深入闡述赠堵,敬請(qǐng)期待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末法褥,一起剝皮案震驚了整個(gè)濱河市茫叭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌半等,老刑警劉巖揍愁,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呐萨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡莽囤,警方通過查閱死者的電腦和手機(jī)谬擦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朽缎,“玉大人怯屉,你說我怎么就攤上這事《祝” “怎么了锨络?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)狼牺。 經(jīng)常有香客問我羡儿,道長(zhǎng),這世上最難降的妖魔是什么是钥? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任掠归,我火速辦了婚禮,結(jié)果婚禮上悄泥,老公的妹妹穿的比我還像新娘虏冻。我一直安慰自己,他們只是感情好弹囚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布厨相。 她就那樣靜靜地躺著,像睡著了一般鸥鹉。 火紅的嫁衣襯著肌膚如雪蛮穿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天毁渗,我揣著相機(jī)與錄音践磅,去河邊找鬼。 笑死灸异,一個(gè)胖子當(dāng)著我的面吹牛府适,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肺樟,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼檐春,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了儡嘶?” 一聲冷哼從身側(cè)響起喇聊,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹦狂,沒想到半個(gè)月后誓篱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凯楔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年窜骄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摆屯。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邻遏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虐骑,到底是詐尸還是另有隱情准验,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布廷没,位于F島的核電站糊饱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颠黎。R本人自食惡果不足惜另锋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望狭归。 院中可真熱鬧夭坪,春花似錦、人聲如沸过椎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疚宇。三九已至竞惋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灰嫉,已是汗流浹背拆宛。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留讼撒,地道東北人浑厚。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像根盒,于是被迫代替她去往敵國(guó)和親钳幅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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