2010-10-21 107 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