【问题标题】:How to detect diconnected Duplex Polling clients如何检测断开的双工轮询客户端
【发布时间】:2010-11-10 19:44:17
【问题描述】:

我关注了 Tomek Janczuk 的 Pub/sub sample using HTTP polling duplex WCF channel,但我注意到当客户端通过关闭浏览器断开连接时,服务不会注意到下一次回调。我本来预计会出现异常或说端点不再存在的东西。

您如何知道客户何时离开,从而停止向该客户发布?

【问题讨论】:

  • 回调方法是“OneWay”吗?在 OperationContract 属性上将 IsOneWay 设置为 false 会使服务器检测到超时吗? (评论不回答,因为我不确定)

标签: silverlight wcf pollingduplexhttpbinding


【解决方案1】:

要确定:不可能

当一个 TCP 连接关闭时(作为 HTTP 调用的基础),一个特殊的 TCP 消息被发送到服务器 - FIN 包。尽管 HTTP 是无状态的,但底层 TCP 连接是有状态的并且通过保持活动状态,底层 TCP 连接通常保持打开状态。如果客户端被释放,则 TCP 连接将关闭,并且通常会向服务器发送一条消息。但如果它崩溃或它的网络断开连接,它就没有时间这样做。所以总而言之,你永远无法确定。

Here 了解更多信息。

【讨论】:

  • 一句话,我喜欢这个答案。 :-)
【解决方案2】:

似乎有一个令人不满意但简单的解决方案:如果客户端回调超时,请不要再次调用它。

在我的系统中,我还实现了手动“检查”调用 - 每 n 秒,服务器通过回调通道为每个注册的客户端调用一个无参数方法,只是为了查看客户端是否还在那儿。我开始怀疑这是否真的是一个好主意 - 我遇到了一个新问题,即回调超时不断发生,因为我在调试器中暂停了客户端。

【讨论】:

  • 在我最初的测试中,问题是我没有得到超时。我正在玩一种类似于你的方法,除了相反。客户端“ping”服务器,如果服务器在设定的时间内没有收到他们的消息,他们就会被排除在列表之外,我认为这类似于 asp.net 会话管理。
  • @Ralph - 我使用的是 netTcpBinding(它是一个胖客户端,而不是 Silverlight)。也许 PollingDuplexHttp 绑定只是没有超时,在这种情况下,您描述的解决方案将是唯一的选择。
【解决方案3】:

很难,几乎不可能(由于 SL 双工功能有限)。我们已经在我们的服务中实现了一个用户列表,并且我们添加了一个属性“IsDisconnected”和 LastCommunicationTime,一旦 WCF 服务在尝试在用户的 Outgoing-Message-Queue 中添加消息时超时,并且失败并引发异常超时。我们标记“IsDisconnecte=true”,下次不要尝试将消息发送给该用户。

另一个线程一直在查看它,如果它注意到 LastCommunicationTime 已超过时间值且 IsDisconnected=true,它将从列表中删除用户,除非同一用户尝试在此时间段内再次连接(我们通过其 UserId 来识别)。

我们手动做了很多事情来处理这个问题,因为它使 WCF 服务变得如此繁忙。

【讨论】:

  • 我最终采用了非常相似的模式。
  • 但是请记住:这会带来另一个问题,服务器现在太聪明了,随时准备踢出用户:),那些没有消失但非常沉默但不知何故他们的“制造”的用户呢?连接调用失败”并且他们的客户端通道出现故障,在这种情况下,他们将不得不再次打开通道,从而为他们提供新的会话 ID,并且该通道对于服务器来说将是新的。因此,一旦再次在服务器上注册,服务器应该从 List 中删除旧用户项目并添加一个新用户项目/或用新用户项目更新它(ClientCallback Channel 非常重要)
  • 当客户端的通道发生故障时,原因是“当建立连接请求失败时”。服务器不会立即知道它。当 serverPooltimeout 超过时,Client.ChannelFaulted 在服务器上触发。如果您知道我的意思,那是“WCF 服务的盲目行动”。虽然我不确定 serverPooltimeout 在那种情况下是否 100%,但老实说,我发现它有点随机。
【解决方案4】:

我遇到了这个问题,并使用以下代码创建了一个删除断开连接的客户端的线程。它工作正常,但会在 10-15 分钟后从客户端列表中删除断开连接的客户端(这对我来说没问题)。

    new Thread(new ThreadStart(() =>
    {
        while (SilverlightClients != null)
        {
                lock (SilverlightClients)
                {
                    SilverlightClients = SilverlightClients.Where(d => (d.Callback as IContextChannel).State != CommunicationState.Opened).ToList();
                }

            Thread.Sleep(1000);
        }
    })) { Name = "Thread Remove Disconnected Clients" }.Start();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-15
    • 2014-04-14
    • 2011-05-05
    • 2015-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    相关资源
    最近更新 更多