使用 WCF 和 TCP 保持活动状态?

KeepAlive with WCF and TCP?

提问人:Banshee 提问时间:11/4/2014 最后编辑:Banshee 更新时间:5/17/2018 访问量:17992

问:

我有一个 Windows 服务托管一个高级 WCF 服务,该服务通过 TCP(netTCP) 与 protobuf.net 通信,有时也与证书通信。

receiveTimeout 设置为 infinite,以永远不会因非活动状态而断开连接。但据我了解,无论如何连接都可能被断开,所以我创建了一个简单的双向 keepalive 服务方法,客户端每 9 分钟调用一次以保持连接处于活动状态。连接永不中断非常重要。

这是正确的方法吗?或者我可以简单地删除我的 keep live,因为 receiveTimout 设置为无限?

编辑:WCF 服务的当前 app.config:http://1drv.ms/1uEVKIt

C# WCF TCP 保持活动状态

评论

0赞 Luiz Felipe 11/4/2014
如果您打算保持连接打开,则必须定期发送 ping 数据包,否则状态满路由器可能会因不活动而断开连接。
0赞 Banshee 11/4/2014
好的,我怎么知道这个ping必须多久发送一次?
0赞 usr 11/4/2014
当连接因暂时性错误而断开时会发生什么情况?你无法阻止它。
0赞 Banshee 11/4/2014
我怀疑如果连接因超时而中断,它也将是一个 timoutException,但我不确定。但是,如果连接断开,确实有办法在不进行新连接的情况下保持其活动状态。如果一个通道出现故障,就不可能做任何事情(我知道的)。
0赞 Erik Funkenbusch 11/5/2014
@LuizFelipe - 如果您正确配置了可靠的会话,则不会,很少有人做对。

答:

45赞 Erik Funkenbusch 11/5/2014 #1

不。这被广泛误解了,不幸的是,那里有很多错误的信息。

首先,“无限”是一种半有效值。有两个特殊的配置序列化程序将“Infinite”转换为 or (所以它们无论如何都不是真正的“无限”),但并不是 WCF 中的所有内容都能识别这一点。因此,最好始终使用时间值显式指定超时。TimeSpan.MaxValueint.MaxValue

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

通过拥有自己的“keepalive”机制,您实际上将服务的负载增加了一倍,并且您实际上可以产生比它解决的问题更多的问题。

第三,在使用可靠会话时,使用 .这做了两件事。首先,它控制基础结构 (keepalive) 消息的发送频率。它们以超时值的一半发送,因此如果将其设置为 18 分钟,则它们将每 9 分钟发送一次。其次,如果在非活动超时期间未收到任何基础结构或操作消息(即数据协定中的消息),则连接将中止,因为可能存在问题(一侧崩溃、网络问题等)。inactivityTimeoutreliableSession

receiveTimeout是连接中止之前无法接收任何操作消息的最长时间(默认值为 10 分钟)。将此值设置为较大的值(在 24 天附近的某个位置)可保持连接正常,将 inactivityTimeout 设置为较小的值(同样,默认值为 10 分钟)(小于网络路由器从非活动状态断开连接之前最大时间的 2 倍的时间)可保持连接处于活动状态。Int32.MaxValue

WCF 将为您处理所有这些问题。然后,只需订阅“连接已中止”消息,即可了解连接何时因实际原因(应用程序崩溃、网络超时、客户端断电等)而断开,并允许您重新创建连接。

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

注意:在 inactivityTimeout 过期(或尝试使用连接)之前,您可能不会收到连接中止事件。请注意这一点,并相应地设置超时。

Internet 上的大多数建议是将 receiveTimeout 和 inactivityTimeout 都设置为 Infinite。这有两个问题,首先基础设施消息没有及时发送,因此路由器会断开连接......强迫你自己做 keepalives。其次,较大的非活动超时意味着它无法识别连接何时合法断开,您必须依靠该 ping 中止来了解何时发生故障。这一切都是完全不必要的,实际上甚至会使您的服务更加不可靠。

另请参阅:如何正确配置 WCF NetTcp 双工可靠会话?

评论

1赞 Banshee 11/5/2014
谢谢!从我所读到的内容来看,reliableSession 与 TCP 协议本身相同,但在另一个层面上,这就是我们将其设置为 enabled=false 的原因。如果我不使用 reliableSession,我将需要我自己的 KeepAlive。这个 KeepAlive 非常简单,它所做的只是每隔一段时间调用一个空服务方法,比如说 9 分钟,以确保连接处于活动状态。如果失败,请关闭应用程序。我在哪里可以阅读更多关于您发布的所有信息?我以前找过这个,但从未找到。我仍然不确定要精确设置哪些设置以及它可以产生什么开销?
0赞 Erik Funkenbusch 11/5/2014
@Banshee - 如果按照我提到的正确配置,可靠的会话将是开销最小的,也是最可靠的。通过关闭它并自己动手,您将本质上是低级函数的内容强制进入您的应用程序域。如果自己这样做,您将丢失重要的元数据、跟踪和诊断报告以及性能统计信息。换句话说,你正在使用一辆高性能的赛车,然后拆掉发动机,在里面装上一个卡丁车发动机,然后想知道为什么它没有性能。
0赞 Erik Funkenbusch 11/5/2014
@Banshee - 正如我所说,这没有很好的记录,而且那里有很多错误信息。我在这里所说的内容是通过多年的反复试验、追踪源代码、阅读各种相互矛盾的文档并找出缺少什么来学习的。可靠的会话,如我所展示的那样配置,运行良好。但是你必须确切地了解它的作用,因为文档不完整、误导、错误或不存在。
3赞 Erik Funkenbusch 11/9/2014
@Banshee - 对不起,我的意思是 24 天,而不是 24 小时。您无法防止断开连接的发生。总会有一些你无法控制的情况,比如网络路由故障。保持连接不间断的可能性越大,保持连接打开的时间越长。最终,即使只是安装补丁并重新启动服务器,也会出现一些情况。当连接断开时,您仍然需要一种方法来重新连接。如果您在 24 天内没有通过连接拨打一个电话,我不得不怀疑保持它有多重要。
1赞 Kyberias 4/11/2017
来自 MSDN 文档:TimeSpan.MaxValue 实际上是 10,675,199 天(30 000 年)。