由于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í)行邏輯模型圖如下:
這張圖告訴我們幾點(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)座菠。它借助了
- 一層三元組[module_id,module_item,module_tag]來組成一個(gè)數(shù)據(jù)集(DataSet也可以稱作Document)狸眼。
- 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ù)拓萌。
- 操作系統(tǒng)的消息循環(huán)岁钓,包裝成事件通知。
一圖勝千言如下圖:
通過圖示具體實(shí)現(xiàn)如下:
- 創(chuàng)建一個(gè)無窗口的句柄用來作為異步事件派發(fā)的基礎(chǔ)微王,即底層最終是借助windows操作系統(tǒng)的消息循環(huán)來封裝上層的Event事件的派發(fā)的屡限,支持同步/異步派發(fā)(即SendMessage/PostMessage)。
- 生成一個(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é)議交集不是那么大,但是想想還是放這里比較適份氧。
如圖:
從這幅圖可以簡(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è)參考
- OC平臺(tái)OS層的基于C的 BSD socket茬祷,這一層面提供的是socket原生態(tài)的方法清焕,可以最大程度的控制網(wǎng)絡(luò)編程,但是工作量也是最大的祭犯,和windows TT采用C/C++ 進(jìn)行socket編程差不多秸妥。
- 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í)就是這一層最盅,所以這里還是需要去深入研究上面的坑突雪。
- OC平臺(tái)最上層提供的Bonjour庫(kù),同學(xué)們可以自行去看下 Networking and Bonjour on iPhone
- 另辟蹊徑不走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è)流程圖吧:
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的思路是這樣的(以登陸業(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)期待。