2010-10-21 106 views
3


也許這看起來可笑,但是這是問題,至少對我來說Wcf Duplex:檢索客戶端連接?

我寫雙工WCF服務,我的服務,我需要得到積極的客戶服務,並將其保存,並在與發生特殊事件我打電話特定的客戶端併爲其發送一些值。所以我定義字典並保存客戶端。 (用這種方法客戶端調用)

public static Dictionary<int, IServiceCallbak> ActiveClients; 
    public void IConnect(int SenderId) 
    { 
      if (ActiveClients == null) 
       ActiveClients = new Dictionary<int, IServiceCallbak>(); 
      Client = OperationContext.Current.GetCallbackChannel<IServiceCallbak>(); 
      if (ActiveClients.Count(ac => ac.Key == SenderId) > 0) 
       ActiveClients.Remove(SenderId); 
      ActiveClients.Add(SenderId, Client); 
    } 

所以後來當我需要從字典中尋找客戶,並調用具體的方法:Client.DoSomthing().
此外,當客戶想要退出時,它調用IDisconnect方法,它將從詞典中刪除客戶端。

所以我管理服務中的活動客戶端!

But there is problem in client for managing themselves 經過一段時間後,在app.config定義的服務連接將被關閉,您應該續約,然後打開服務。

因此,在這種情況下:
1)是否有重新創建任何解決方案,並在客戶端中打開服務對象automatically
2),或者在服務器端,當服務需要致電客戶,從字典中查詢客戶服務對象的狀態,並重新從服務器端(Ridiculous-solution

連接編輯

我認爲更好的解決方案是要處理Suggestion 1,我不知道怎麼回事!!!
因此,現在的問題是:Is way exist to do Suggestion 1 Or not?以前我描述建議1在評論:
「並自動引用這種情況下的事件(如關閉或中止),但我沒有找到任何這樣做在Service-Client 「

+0

關於建議'1',如果我重新創建服務對象,並調用服務,有很大的問題,服務會發現客戶端具有不同的服務回調通道。所以我的意思是,我爲服務創建了具有相同Service-Callback-Channel的相同對象。並自動引用此事件(如關閉或中止),但我在Service-Client中找不到這樣的事情,但在Service-channel'Closing'中有一個事件。那麼有什麼方法可以使用它? – Rev 2010-10-24 08:51:04

回答

4

爲了防止服務器端關閉連接,您可以在客戶端可以定期調用的合約中設置Heartbeat()方法。然而,這並不理想,因爲底層套接字可能會下降,而這無助於補救。

只要你的建議1)如果在客戶端你從ClientBase繼承,你有點卡住了,直到你調用一個方法來路由到服務,沒有指出可能會出現問題。你將不得不包裹中的呼叫try/catch語句,然後使用一些重新連接邏輯:

public class MyClass : ClientBase<IContract>, IContract 
{ 
    public void ServiceMethod(String data) { 
     try { 
      base.Channel.ServiceMethod(data); 
     } 
     catch (CommunicationException ce) { 
      // Perform some reconnect logic here 
      base.Channel.ServiceMethod(data); 
     } 
    } 
} 

您的建議,評論2)是正確的,如果有服務器端和客戶端,它們很可能之間的任何防火牆不允許連接

編輯: 爲了擴展我對1)的建議,當對服務的調用失敗並出現CommunicationException時,您需要創建一個新連接。最簡單的方法是創建在構造函數中的服務通道,然後創建另一個當調用失敗:

class ServiceClient { 
    Service1Client mService; // Class generated by VS tool 
    public ServiceClient() 
     : base() { 
      mService = new Service1Client(); 
    } 
    #region IService1 Members 
    public string GetData(int value) { 
     CommunicationState state = mService.State; 
     if (state == CommunicationState.Closed || state == CommunicationState.Faulted) { 
      mService = new Service1Client(); 
     } 
     try { 
      // Note: The state checked above may not be accurate, 
      // hence the try...catch 
      return mService.GetData(value); 
     } 
     catch (CommunicationException) { 
      mService = new Service1Client(); // Reconnect logic 
      return mService.GetData(value); // If it fails again we are out of luck... 
     } 
    } 
    #endregion 
} 

EDIT2:

在WCF會話是由客戶端如果處理之間的會話客戶端和服務丟失,我知道無法從客戶端或服務恢復該會話。不幸的是,你被困在這裏。

如果服務想通過回調發送一個會話中斷,簡單地說,它不能。由於網絡的工作方式,服務可能不知道實際的客戶端地址。這個和其他各種問題(如防火牆)意味着嘗試從服務中重新建立與客戶端的連接並不現實。該服務的唯一方法是存儲要發送給客戶端的數據,並在服務檢測到客戶端已重新連接時發送它。

不能保證客戶端將知道底層套接字丟棄,直到客戶端試圖通過套接字發送某個東西,因此try ... catch。一旦意識到連接斷開,從客戶端重新創建頻道是我知道處理該問題的唯一途徑;這是代碼示例的作用。

心跳想法是主動處理斷開連接的一種方式。其效率取決於您需要檢測連接斷開的速度以及有多少客戶端。連接的客戶越多,心跳就必須越長,以免在服務中給網絡帶來負擔。

EDIT3:

後一些額外的挖掘有可能是一種方法做你自動想要什麼。您可以創建所謂的Reliable Session。激活這涉及在配置創建額外的條目:

<netTcpBinding> 
    <binding> 
     <reliableSession ordered="Boolean" 
        inactivityTimeout="TimeSpan" 
        enabled="Boolean" /> 
    </binding> 
</netTcpBinding> 

它也可用於HTTP綁定相關的,檢查出的鏈接的功能,微軟文檔。

+0

@Steve'心跳'我喜歡那樣,但正如你所說這不是理想的方式。所以我必須爲此制定計時器(我不喜歡計時器的特別服務)。感謝您的關注!那幫了我:) – Rev 2010-10-24 08:55:00

+1

看到我的回答編輯 – 2010-10-24 15:36:54

+0

@Steve,再次感謝。我認爲你創建自助服務客戶端基類這一點,而我使用添加服務引用和VS生成該類。所以問題是我可以更改這個生成的類? – Rev 2010-10-25 08:54:33