2010-11-10 72 views
6

我遵循Tomek Janczuk的Pub/sub sample using HTTP polling duplex WCF channel,但我注意到当客户端通过关闭浏览器断开连接时,服务在下一次回调时不会注意到。我本来期望有一个例外或者说端点不再存在。如何检测双连接双工轮询客户端

你怎么知道客户端何时离开,以便停止发布给客户端?

+0

回调方法是“单向”吗?将OperationContract属性设置为服务器检测超时时,将IsOneWay设置为false? (评论不回答,因为我不确定) – 2010-11-11 22:42:07

回答

3

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

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

+0

在我最初的测试中,问题是我没有超时。我正在尝试一种类似的方法,除非相反。客户端“ping”服务器,如果服务器在设定的时间内没有收到消息,他们就不在列表中,我相信这与asp.net会话管理类似。 – 2010-11-11 13:37:36

+0

@Ralph - 我正在使用netTcpBinding(这是一个胖客户端,而不是Silverlight)。也许PollingDuplexHttp绑定不会超时,在这种情况下,您所描述的解决方案将是唯一的选择。 – 2010-11-11 22:54:14

5

要知道肯定:不可能

当一个TCP连接关闭时(一个HTTP调用的底层),一个特殊的TCP消息被发送到服务器 - FIN数据包。虽然HTTP是无状态的,但底层TCP连接是有状态的并且保持活动状态,底层TCP连接通常保持打开状态。如果客户端被丢弃,则TCP连接关闭,并且通常会向服务器发送消息。但是如果它崩溃或者它的网络断开连接,它就没有时间去做这件事。所以总之,你永远无法确定。

Here欲了解更多信息。

+0

总之,我喜欢这个答案。 :-) – 2012-01-28 15:20:11

3

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

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

有很多事情我们手动处理这个问题,因为它使WCF服务非常繁忙。

+0

我最终采用了非常相似的模式。 – 2010-11-10 20:29:27

+0

但是请记住:这会产生另一个问题,服务器现在太聪明了,总是准备把用户踢出去:),那些没有离开但非常沉默,但他们的“连接呼叫失败”的用户以及他们的客户频道出现了问题,在这种情况下,他们不得不再次打开频道,这给他们一个新的会话Id,并且该频道对于服务器来说是新的。因此,一旦服务器在服务器上注册,服务器应该从列表中删除旧用户项并添加一个新的/或用新的用户项更新(ClientCallback Channel非常重要) – 2010-11-10 21:02:40

+0

当客户端的通道出现故障时导致“连接请求失败“。服务器不知道它立即。当serverPooltimeout超过时,Client.ChannelFaulted会在服务器上触发。如果你知道我的意思,这是一个“WCF服务的盲目移动”。虽然我不确定serverPooltimeout在这种情况下是100%,但老实说,我发现它是随机时间。 – 2010-11-10 21:11:16

1

我遇到了这个问题,并创建了一个线程,用以下代码删除断开连接的客户端。它工作正常,但在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(); 
相关问题