2009-12-07 70 views
7

我想在WCF中創建一個簡單的客戶端 - 服務器示例。我用回調做了一些測試,到目前爲止效果很好。我打得四處一點點有以下接口:WCF - 客戶端回調與輪詢「保留訂戶列表」

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IStringCallback))] 
public interface ISubscribeableService 
{ 
    [OperationContract] 
    void ExecuteStringCallBack(string value); 

    [OperationContract] 
    ServerInformation Subscribe(ClientInformation c); 

    [OperationContract] 
    ServerInformation Unsubscribe(ClientInformation c); 
} 

它是一個簡單的例子。稍微調整一下。您可以要求服務器「執行字符串回調」,在這種情況下,服務器反轉字符串並調用所有訂閱的客戶端回調。

現在,問題來了:如果我想實現一個系統,其中所有客戶端都向服務器「註冊」,並且服務器可以「詢問」客戶端是否還活着,您是否會使用回調函數所以不是這個「stringcallback」,而是一種TellTheClientThatIAmSti​​llHereCallback)。通過檢查回調中的通信狀態,我還可以「知道」客戶端是否已經死亡。這種類似的東西:

Subscribers.ForEach(delegate(IStringCallback callback) 
        { 
         if (((ICommunicationObject)callback).State == CommunicationState.Opened) 
         { 
          callback.StringCallbackFunction(new string(retVal)); 
         } 
         else 
         { 
          Subscribers.Remove(callback); 
         } 
        }); 

我的問題,以另一種方式:

  • 服務器可能有3個客戶
  • 客戶端A死了(我拉的筆記本電腦的插頭)
  • 服務器死亡並重新聯機
  • 新客戶端出現

所以基本上,你會使用回調來驗證客戶的「仍然活着的狀態」,或者你會使用輪詢和跟蹤「多久我沒有聽說過客戶端」...

+0

如何連接到WCF Sever的?你使用TCP嗎?這將改變如何實施聯營。 – 2009-12-15 17:33:39

回答

0

我有類似的情況使用WCF和回調。我不想使用輪詢,但我使用的是「可恢復」協議,所以如果客戶端死了,那麼它會掛起服務器,直到超時並崩潰。

我不知道這是最正確還是優雅的解決方案,但我所做的是在服務中創建一個類來表示客戶端代理。該類的每個實例都包含對客戶端代理的引用,並且只要服務器設置類的「消息」屬性就會執行回調函數。通過這樣做,當客戶端斷開連接時,單獨的包裝類將獲得超時excetpion,並從服務器的偵聽器列表中刪除自己,但服務不必等待它。這實際上並沒有回答你關於確定客戶端是否存在的問題,但它是構建服務的另一種方式來增加這個問題。如果您需要知道客戶端何時死亡,您可以在客戶端封裝器從偵聽器列表中刪除自己時啓動。

0

我還沒有嘗試通過線路使用WCF回調,但我已經使用它們進行了進程間通信。我遇到了一個問題,那就是發送的調用的調用在同一個線程上結束,並且在存在依賴於同一線程的調用時使服務死鎖。

這可能適用於您目前擁有的問題,因此這裏是我必須要解決的問題。

將這個屬性到WCF服務器implemetation類的服務器和客戶端

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class WCFServerClass 

的ConcurrencyMode.Multiple使得在自己的線程每次調用的過程,應該可以幫助您與服務器鎖定了當客戶死亡直到它超時。

我也做了一定要使用一個線程池在客戶端,以確保有在客戶端沒有線程問題

3

您可以通過檢測大多數更改連接狀態ClosedClosingFaultedICommunicationObject的事件。您可以在設置回調的同時掛鉤它們。這肯定比投票更好。

IIRC,Faulted事件只會在之後觸發您實際嘗試使用回調(失敗)。因此,如果客戶端消失 - 例如,硬重啓或關機 - 那麼您將不會立即得到通知。但你需要成爲嗎?如果是這樣,爲什麼?

一個WCF回調可能會失敗,在任何時候,你總是需要記住這你的腦海裏。即使客戶端和服務器都正常,但由於發生異常或網絡中斷,您仍然可能會遇到故障通道。或者,也許客戶在您最近一次投票和您當前的操作之間有時會脫機。問題是,只要你在防守方面編碼你的回調操作(無論如何這是一個很好的做法),那麼上面的事件通常足以滿足大多數設計。如果因任何原因發生錯誤(包括客戶端未能響應),則Faulted事件將啓動並運行您的清理代碼。

這是我會稱之爲被動/偷懶的做法,並要求編碼和網絡喋喋不休比輪詢或保持有效的辦法少。

+0

這就是我所需要的類似功能(有點頻繁)所做的。 – kyoryu 2009-12-16 01:02:32

2

如果啓用了可靠的會話,WCF內部維護一個保活控制機制。它通過隱藏的基礎設施測試消息定期檢查另一端是否在那裏。這些檢查的時間間隔可以通過ReliableSession.InactivityTimeout屬性來影響。如果設置屬性,比如20秒,然後ICommunicationObject.Faulted事件將被在另一側發生故障的服務後引發約20〜30(最大)秒。

如果您想確保客戶端應用程序始終保持「自動連接」狀態,即使在臨時服務中斷後,您也可能想要使用一個工作線程(來自線程池)重複嘗試創建新的代理實例在客戶端,並在那裏引發Faulted事件之後調用會話啓動操作。

作爲第二種方法,因爲你是無論如何實施工作線程機制,你也可能會忽略的故障事件,讓客戶端應用程序的整個生命週期內的工作線程循環。讓線程重複檢查代理狀態,並在狀態出現故障時嘗試進行修復工作。使用第一種或第二種方法,可以實現服務總線體系結構(中介模式),保證所有客戶端應用程序實例始終準備好在服務運行時接收「自發」服務消息。當然,這隻有在可靠會話「as as such」配置正確才能開始(使用具有會話能力的綁定,並應用ServiceContractAttribute.SessionMode,ServiceBehaviorAttribute.InstanceContextMode,OperationContractAttribute.IsInitiating和OperationContractAttribute。以有意義的方式終止屬性)。