2009-12-07 68 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。以有意义的方式终止属性)。