代码之家  ›  专栏  ›  技术社区  ›  Rev

wcf duplex:检索客户端连接?

wcf
  •  3
  • Rev  · 技术社区  · 14 年前

    您好!
    也许这看起来很荒谬,但至少对我来说这是个问题

    我编写了双工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:
    “并自动引用此案例的事件(如关闭或中止),但在服务客户端中找不到执行此操作的任何内容。”

    1 回复  |  直到 14 年前
        1
  •  4
  •   Steve Ellinger    14 年前

    为了防止服务器端关闭连接,可以在契约中设置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
    }
    

    编辑2:

    在WCF中,会话由客户机处理,如果客户机和服务之间的会话丢失,我不知道从客户机或服务恢复该会话的方法。不幸的是,你被困在这里。

    如果服务想要通过一个中断会话的回调发送,简单地说,它不能。因为网络的工作方式,服务可能不知道实际的客户机地址。这和其他各种问题(如防火墙)意味着尝试从服务重新建立与客户机的连接是不现实的。服务的唯一方法是存储它要发送给客户机的数据,并在服务检测到客户机已重新连接时发送。

    在客户机尝试通过套接字发送某些内容之前,不能保证客户机知道底层套接字将丢失,因此会出现try…catch。从客户机重新创建通道,一旦它发现断开的连接,这是我所知道的处理问题的唯一方法;这就是代码示例所做的。

    心跳是一种主动处理断开连接的方法。它的效率取决于您对检测断开连接的速度以及存在多少客户机的要求。连接的客户机越多,心跳就越长,这样您就不会在服务的网络上增加负载。

    EdTe3:

    在进行了一些额外的挖掘之后,可能会有一种方法可以自动完成您想要的工作。您可以创建一个 Reliable Session . 激活此项涉及在配置中创建其他条目:

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

    它还可用于与HTTP相关的绑定,请查看指向该功能的Microsoft文档的链接。

    推荐文章