使用WCF和TCP进行KeepAlive?

15
我有一个托管高级WCF服务的Windows服务,使用 TCP(netTCP)和protobuf.net通信, 有时也会使用证书。
接收超时(receiveTimeout)被设置为无限以防止由于不活动而断开连接。但据我所知,连接仍可能被断开,因此我创建了一个简单的双向保持活动服务方法,客户端每9分钟调用一次以保持连接处于活动状态。连接永远不能断开非常重要。
这是正确的方式吗?或者可以简单地删除我的保持活动,因为接收超时(receiveTimeout)已设置为无限?
编辑: WCF服务的当前app.config: http://1drv.ms/1uEVKIt

如果您打算保持连接开放状态,必须发送定期的ping数据包,否则有状态路由器可能会因为不活动而断开连接。 - Luiz Felipe
好的,我怎么知道这个ping需要发送多少次? - Banshee
当连接由于瞬态错误而断开时会发生什么?你无法防止这种情况。 - usr
我怀疑如果连接由于超时而中断,它也将是一个超时异常,但我对此不确定。然而,如果连接中断,没有办法使其保持活动状态而不进行新的连接。如果通道出现故障,则无法对其进行任何操作(至少我不知道如何)。 - Banshee
WCF服务的app.config链接是否有效? - SDK
显示剩余3条评论
1个回答

45

不是的。这个被广泛误解了,不幸的是有很多错误信息在外面。

首先,“无限”是一种半有效的值。有两个特殊配置序列化程序将“无限”转换为TimeSpan.MaxValueint.MaxValue(所以它们实际上并不是“无限”的),但是WCF中的并不是所有内容都能够识别它。因此最好使用时间值明确指定超时。

其次,在您的服务中不需要“保持活动”的方法,因为WCF提供了所谓的“可靠会话”。如果添加 <reliableSession enabled="true" />,那么WCF将通过“基础结构消息”提供自己的保持活动机制。

通过拥有您自己的“保持活动”机制,您实际上会使您的服务负载加倍,并且可能会创建更多问题而不是解决问题。

第三,当使用可靠会话时,您使用reliableSessioninactivityTimeout设置。这做两件事情。首先,它控制基础设施(保持活动)消息发送的频率。它们在timeout值的一半处发送,所以如果您将其设置为18分钟,则它们将每9分钟发送一次。其次,如果没有接收到基础设施或操作消息(即作为您数据契约的一部分的消息)在不活动超时期内收到,则连接将被中止,因为可能存在问题(一方已崩溃,存在网络问题等)。

receiveTimeout是在连接中无法接收任何操作消息之前的最长时间(默认值为10分钟),在这之后会中止连接。将其设置为大值(Int32.MaxValue某处大约为24天)可以保持连接,将inactivityTimeout设置为较小值(再次,默认值为10分钟)(小于网络路由器在不活动情况下断开连接的最长时间的2倍时间),可以保持连接的活性。

WCF会为您处理所有这些内容。您可以订阅连接中止消息,以知道何时出现真正的连接断开(应用程序崩溃、网络超时、客户端断电等),并允许您重新创建连接。

此外,如果您不需要有序消息,请设置 ordered="false" ,因为这会大大减少可靠会话的开销。默认值为true。

注意:在未活动时间过长(或尝试使用连接)之前,可能不会收到连接中止事件。请注意此问题,并相应地设置超时时间。

互联网上的大多数建议是将receiveTimeout和inactivityTimeout都设置为Infinite。这有两个问题,首先基础设施消息无法及时发送,因此路由器将放弃连接...迫使您进行自己的保持活动操作。其次,大的不活动超时意味着它无法识别连接合法地断开,而您必须依赖于ping终止来知道故障发生的情况。这完全是不必要的,并且实际上甚至可能使您的服务更加不可靠。

也请参见:如何正确配置WCF NetTcp Duplex可靠会话?


1
根据我所读的,reliableSession 执行的操作与 TCP 协议本身相同,但处于另一个级别,这就是为什么我们将其设置为 enabled=false。如果我不使用 reliableSession,那么我需要自己的 KeepAlive。这个 KeepAlive 很简单,它只需每隔 9 分钟调用一个空服务方法,以确保连接正常。如果失败,则关闭应用程序。我在哪里可以阅读更多关于您发布的所有信息?我曾经搜索过,但从未找到。我仍然不确定要设置哪些设置以及可能会创建什么开销? - Banshee
3
@Banshee - 抱歉,我的意思是24天而不是24小时。你无法阻止断开连接的发生。总会有一些情况超出你的控制范围,例如网络路由故障。长时间保持连接不间断是极不可能的,即使你将其保持打开状态。最终,某些条件将发生,甚至只是安装补丁和重新启动服务器。当连接中断时,你仍然需要一种重新连接的方法。如果你在24天内没有通过连接进行任何一次调用,我必须怀疑保持连接的重要性。 - Erik Funkenbusch
1
根据MSDN文档,TimeSpan.MaxValue实际上是10,675,199天(30,000年)。 - Kyberias
@Kyberias - 没错,我在上面打错了。应该是Int32.MaxValue,而不是TimeSpan.MaxValue。receiveTimeout的最大值为24.20:31:23.6470000。这是Int32.MaxValue,表示最大的毫秒数,如果你计算(2^31) / 1000 / 60 / 60 / 24 = 上面的数字。 - Erik Funkenbusch
我在https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/reliablesession中找不到reliableSession启用属性。它不再支持吗? - Michael Freidgeim
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接