WCF從理論到實(shí)踐(8):事件廣播
上文討論了WCF中三種消息交換模式,one-way,request/reply,duplex。前兩項(xiàng)比較簡(jiǎn)單,無(wú)需多言,duplex相對(duì)比較復(fù)雜,上文只是實(shí)現(xiàn)了簡(jiǎn)單的回調(diào),在真正應(yīng)用的時(shí)候,還有許多值得注意之處,本文就結(jié)合一個(gè)實(shí)際的應(yīng)用例子來(lái)談?wù)撓耫uplex的具體應(yīng)用和非常值得我們注意的地方。
本文的出發(fā)點(diǎn)
通過(guò)閱讀本文,您能理解以下知識(shí):
- 如何實(shí)現(xiàn)一個(gè)基于duplex的事件廣播
- 解析在實(shí)現(xiàn)duplex事件廣播中的幾個(gè)問(wèn)題
- 初步探討一下異步
本文適合的讀者
本文屬于中等難度的文章,需要有WCF消息交換和windows應(yīng)用程序開(kāi)發(fā)相關(guān)的基礎(chǔ)知識(shí),有關(guān)WCF消息交換,請(qǐng)閱讀http://www.rzrgm.cn/jillzhang/archive/2008/02/17/1071521.html
如何實(shí)現(xiàn)一個(gè)基于duplex的事件廣播
在討論如何實(shí)現(xiàn)之前,先看一下本文的范例所要實(shí)現(xiàn)的功能是什么?本文的范例實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的分布式任務(wù)管理系統(tǒng),簡(jiǎn)單的說(shuō),它是在服務(wù)端(Server Point)執(zhí)行任務(wù)(Job),并且將任務(wù)的信息呈現(xiàn)給客戶端。它有如下特征:
- 通過(guò)調(diào)用服務(wù)端的Accept(),客戶端能連接上服務(wù)端,并保持會(huì)話。
- 客戶端在啟動(dòng)的時(shí)候,可以通過(guò)遠(yuǎn)程調(diào)用GetJobs()來(lái)獲取當(dāng)前服務(wù)端中全部的任務(wù),并將這些任務(wù)在客戶端窗體中用列表控件呈現(xiàn)出來(lái)
- 客戶端能通過(guò)調(diào)用AddJob()向服務(wù)端添加任務(wù),當(dāng)服務(wù)端完成添加操作之后,引發(fā)添加完成的事件,并向全部的客戶端廣播該事件
- 當(dāng)客戶端服務(wù)端發(fā)來(lái)的添加新任務(wù)事件廣播的時(shí)候,客戶端將新增任務(wù)添加到列表控件加以呈現(xiàn)
- 客戶端可以命令服務(wù)端執(zhí)行具體某個(gè)任務(wù),當(dāng)任務(wù)在開(kāi)始執(zhí)行和執(zhí)行結(jié)束后,服務(wù)端都會(huì)像全部客戶端廣播任務(wù)的執(zhí)行情況,并且任務(wù)的執(zhí)行和事件的廣播異步執(zhí)行
- 客戶端收到廣播后,便可以更新任務(wù)信息。
和以前文章不同,本文先給出最后實(shí)現(xiàn)的效果
如何您要了解該范例得具體設(shè)計(jì)和實(shí)現(xiàn),可以下載下面的文件進(jìn)行分析:
范例最終實(shí)現(xiàn):/Files/jillzhang/Jillzhang.Event.rar
我這里只列出范例中項(xiàng)目列表
|
項(xiàng)目名稱(chēng) |
項(xiàng)目描述 |
|
|
Jillzhang.Event.Core |
該項(xiàng)目用于定義WCF的契約,主要包括IServer服務(wù)契約,ICallback用于回調(diào)的服務(wù)契約,Job數(shù)據(jù)契約 |
|
|
Jillzhang.Event.Service |
服務(wù)端的具體實(shí)現(xiàn),其中Server實(shí)現(xiàn)了一個(gè)有廣播事件能力的服務(wù)契約 |
|
|
Jillzhang.Event.Host |
服務(wù)的宿主程序,一個(gè)ConsoleApplication |
|
|
Jillzhang.Event.Client |
客戶端實(shí)現(xiàn),用于消費(fèi)服務(wù)端。 |
|
|
Jillzhang.Event.Client2 |
和Jillzhang.Event.Client是一個(gè)實(shí)現(xiàn),但為了驗(yàn)證廣播,可與Jillzhang.Event.Client同時(shí)消費(fèi)服務(wù)端 |
|
解析在實(shí)現(xiàn)duplex事件廣播中的幾個(gè)問(wèn)題
我們知道ConcurrencyMode是控制服務(wù)并發(fā)的,默認(rèn)情況下ConCurrendMode的值為Single,它設(shè)置服務(wù)運(yùn)行在單線程下,當(dāng)上一個(gè)請(qǐng)求未完成之前,服務(wù)是不接受下一個(gè)請(qǐng)求的。而duplex在進(jìn)行回調(diào)的時(shí)候,如果回調(diào)方法沒(méi)有被設(shè)置為 One-Way的交換模式,服務(wù)端是會(huì)等待客戶端對(duì)回調(diào)的響應(yīng)的,這可不是一件好事情,因?yàn)榉?wù)端并不能保證客戶端能正常地執(zhí)行回調(diào)并返回?cái)?shù)據(jù)。更多的情況下,我們期望回調(diào)在發(fā)出后能立即返回,方法有兩個(gè):a)將回調(diào)方法設(shè)置為One-Way交換模式 b)采用多線程。經(jīng)過(guò)我的測(cè)試,當(dāng)回調(diào)方法被設(shè)置了one-way模式后,將ConcurrencyMode設(shè)置為Single是可以實(shí)現(xiàn)duplex雙向通訊的。 要第二種方法也非常簡(jiǎn)單,只需要將ConcurrencyMode設(shè)置為Mutiple.此時(shí)即使回調(diào)方法不是one-way模式,也是可以完成duplex的。值得說(shuō)明一下的是ConcurrencyMode還有中性的屬性:ConcurrencyMode.Reentrant,說(shuō)句心里話,我不喜歡這個(gè)不倫不類(lèi)的家伙,他能實(shí)現(xiàn)在單線程下同時(shí)接受多個(gè)請(qǐng)求,但有利必有弊,這個(gè)家伙不能保證請(qǐng)求事務(wù)的完整性,使用的時(shí)候應(yīng)該謹(jǐn)慎。
2)InstanceContextMode = InstanceContextMode.PerSession卻為何能實(shí)現(xiàn)廣播?
如果將InstanceContextMode設(shè)置為PerSession,我們知道服務(wù)端對(duì)象是針對(duì)每一個(gè)會(huì)話的,也就是說(shuō)每個(gè)會(huì)話會(huì)產(chǎn)生一個(gè)對(duì)象實(shí)例,這樣如果要實(shí)現(xiàn)廣播,我們必須將當(dāng)前服務(wù)包含的會(huì)話信息用一個(gè)列表對(duì)象記錄下來(lái),廣播的時(shí)候,我們遍歷會(huì)話列表,進(jìn)行逐個(gè)回調(diào)。本示例中巧妙的利用了Event可包括多個(gè)委托實(shí)例的特征,一個(gè)靜態(tài)的Event對(duì)象針對(duì)每個(gè)會(huì)話創(chuàng)建一個(gè)委托實(shí)例便可以完成上述的要求。遍歷回調(diào)的方法便可以編寫(xiě)如下:
private void BroadcastEvent(CallbackEventArg e, ServerEventHanlder temp)
{
if (OnStatusChanged != null)
{
foreach (ServerEventHanlder handler in temp.GetInvocationList())
{
handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
}
}
}3)困擾了我半天的問(wèn)題
上篇文章中,已經(jīng)對(duì)duplex有了初步的認(rèn)識(shí),本以為本文的范例實(shí)現(xiàn)會(huì)很順利呢,可有一個(gè)問(wèn)題卻困擾了我半天,在回調(diào)的時(shí)候非常不穩(wěn)定,有時(shí)能回調(diào)4.5次,有時(shí)1,2次之后,再回調(diào)卻沒(méi)了響應(yīng),開(kāi)始百思不得其解,因?yàn)殚_(kāi)始幾次可成功回調(diào),為何會(huì)不穩(wěn)定呢?經(jīng)過(guò)好一番嘗試,也沒(méi)能解決,回調(diào)沒(méi)有響應(yīng),肯定是客戶端與服務(wù)端失去了連接,會(huì)話過(guò)期就會(huì)造成雙方通訊連接的中斷,經(jīng)過(guò)分析,我的系統(tǒng)是這樣的
會(huì)不會(huì)在Accept后Do()方法前的過(guò)程中會(huì)話過(guò)期了呢?后來(lái)經(jīng)過(guò)驗(yàn)證,的確是此處的問(wèn)題,解決方法是通過(guò)設(shè)置操作契約的IsTerminating來(lái)實(shí)現(xiàn)會(huì)話的維護(hù),當(dāng)一個(gè)操作契約的IsTerminating被設(shè)置為false的時(shí)候,該操作不會(huì)導(dǎo)致會(huì)話的中斷,將IServer設(shè)計(jì)如下便解決了我的問(wèn)題 :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace Jillzhang.Event.Core
{
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallback))]
public interface IServer
{
[OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
void Accept(); 
[OperationContract(IsOneWay=true,IsInitiating=false,IsTerminating=false)]
void Do(string jobName);
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
void AddJob(Job job);
[OperationContract(IsOneWay=false,IsInitiating=false,IsTerminating=false)]
List<Job> GetJobs();
}
}
初步探討一下異步
進(jìn)程間通訊是一件很耗時(shí)的事情,如果同步執(zhí)行會(huì)造成線程的阻塞,如果是在服務(wù)端,會(huì)降低服務(wù)的處理能力(這種說(shuō)法可能有些問(wèn)題,我會(huì)進(jìn)一步求證,估計(jì)保留,經(jīng)過(guò)查證多線程在服務(wù)端的好處在于提供對(duì)單個(gè)請(qǐng)求用多個(gè)線程處理的能力,從而防止完成一個(gè)請(qǐng)求之前,無(wú)法接受新的請(qǐng)求),如果是在客戶端,會(huì)給用戶帶來(lái)不好的體驗(yàn)。下面就分別探討一下如何實(shí)現(xiàn)服務(wù)端和客戶端的異步。
在服務(wù)端,一個(gè)事件的異步可以通過(guò)delegate的BeginInvoke和EndInvoke來(lái)實(shí)現(xiàn),具體方法可以參見(jiàn)示例項(xiàng)目Jillzhang.Event.Service中的Server對(duì)象的方法BroadcastEvent方法的實(shí)現(xiàn)
而在客戶端,我們可以起多個(gè)線程,當(dāng)然最方便快捷的辦法就是使用BackGroundWorker后臺(tái)線程來(lái)處理耗時(shí)比較長(zhǎng)的操作了,具體實(shí)現(xiàn)也可以參考Jillzhang.Event.Client項(xiàng)目中的Form1.cs實(shí)現(xiàn)。
本文的參考資料
- http://www.rzrgm.cn/wayfarer/archive/2007/03/08/667865.html
- http://www.rzrgm.cn/caishiqi/archive/2007/10/05/914671.html
- http://msdn.microsoft.com/msdnmag/issues/06/10/wcfessentials/default.aspx
本文中的范例
范例最終實(shí)現(xiàn):/Files/jillzhang/Jillzhang.Event.rar
原來(lái)的示例代碼中,采用的Binding為NetTcpBinding,有朋友問(wèn)用WsDualHttpBinding的時(shí)候出現(xiàn)異常,也作了一個(gè)示例
/Files/jillzhang/Jillzhang.Event_WsDualHttpBinding.rar
出處:http://jillzhang.cnblogs.com/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

通過(guò)閱讀本文,您能理解以下知識(shí):
1)如何實(shí)現(xiàn)一個(gè)基于duplex的事件廣播
2)解析在實(shí)現(xiàn)duplex事件廣播中的幾個(gè)問(wèn)題
3)初步探討一下異步


浙公網(wǎng)安備 33010602011771號(hào)