请原谅明显的自我问答,但此信息被广泛误解,并且几乎总是被错误地回答。所以我想把这些信息放在这里,供人们寻找这个问题的明确答案。
即便如此,仍有一些我无法确定的信息。我将把它放在问题的结尾(如果你对序言不感兴趣,请跳到那个)。
如何正确配置 WCF NetTcp 双工可靠会话?
关于这个主题有很多问题和答案,几乎所有问题和答案都建议inactivityTimeout="Infinite"
在您的配置中进行设置。这似乎不能正常工作,特别是对于 NetTcp 的情况(它可能对 WSDualHttp 绑定正常工作,但我从未使用过这些)。
还有许多其他问题通常与此相关:包括,客户端或服务器意外断开连接后通道没有故障,10 分钟后通道断开连接,通道随机断开连接...尝试打开时通道抛出异常...无法在同一端点上配置元数据...
请注意:下面有两个重要的概念。基础结构消息是 WCF 通信方式的内部消息,并由框架使用以保持事情顺利运行。操作消息是由于您的应用程序执行了某些操作而发生的消息,例如通过网络发送消息。基础设施消息在很大程度上对您的应用程序是不可见的(但它们仍然出现在后台),而操作消息是您的应用程序已采取的操作的结果。
我通过来之不易的反复试验得出的信息。
Infinite
在所有情况下似乎都不是有效的配置设置(当然,Visual Studio 验证架构不知道它)。- 有两个特殊的配置转换器,称为
InfiniteIntConverter
and有时InfiniteTimeSpanConverter
可以将值转换为or ,但我还没有弄清楚这似乎是有效的情况,有时它有效,有时它不有效。更重要的是,一些库似乎允许在配置中,而另一些则不允许,因此您可以在配置的一部分中成功,但在另一部分中失败。Infinite
Int.MaxValue
TimeSpan.MaxValue
Infinite
- 您必须在客户端和服务器上都配置BOTH
inactivityTimeout
和,。receiveTimeout
虽然这些值不必相同,但它们可能应该相同,因为如果它们不同,它们可能会引起混淆。(从技术上讲,如果需要,您可以保留inactivityTimeout
其默认值,但您应该了解它的值以及它的作用) inactivityTimeout
永远不要设置为一个很大的值,更小Infinite
或TimeSpan.MaxValue
.inactivityTimeout
有两个功能(这并没有被广泛理解)。第一个函数定义了通道上可以经过的最长时间而不接收任何“基础设施”或“操作”消息。第二个函数定义发送基础设施消息的时间段(指定时间的一半)。如果在超时期间没有收到任何基础设施或操作消息,则连接被中止。receiveTimeout
仅指定操作消息之间可以经过的最长时间。该值可以设置为较大的值,例如TimeSpan.MaxValue
(特别是如果您的频道在内部通过受信任的网络或通过 vpn 运行)。这个值定义了如果客户端和服务器之间没有活动(除了基础设施消息),可靠会话将“保持活动状态”多长时间。即,您的客户端不会调用接口的任何方法,并且您的服务器不会回调客户端。- 即使您的客户端和服务器之间没有任何操作活动,设置一个短的
inactivityTimeout
和一个大的也可以使您的可靠会话“保持稳定”。receiveTimeout
短暂的不活动超时(我喜欢保持默认的 10 分钟或更短)发送基础设施“ping”消息以保持 TCP 连接处于活动状态,而长接收超时保持可靠会话处于活动状态。同时在断开连接的情况下提供合理的超时。 - 如果您设置
inactivityTimeout
为较大的值,那么可靠会话将不可靠,因为它无法保持 Tcp 连接处于活动状态,也无法验证连接的完整性。在您尝试向该客户端发送消息并发现连接不再存在之前,它不会知道用户是否意外断开连接。这就是为什么许多使用 Infinite 进行此设置的人会在他们的服务中创建“Ping”方法,如果您正确配置了这些设置,这是完全没有必要的。 - 如果您设置
inactivityTimeout
的值大于receiveTimeout
then 它同样也不可靠,因为您仍将受receiveTimeout
for 操作消息的约束。IE。如果您忘记设置receiveTimeout
并将其保留为默认 10 分钟,则如果用户空闲 10 分钟,则连接将中止。 - 当客户端或服务器意外断开连接(应用程序崩溃、网络故障、有人绊倒电源线等)时,对方可能不会立即注意到。我
ChannelFaulted
在各种测试情况下附加了各种事件处理程序,有时连接会立即出现故障......其他时候它似乎根本没有故障。我通过反复试验发现的是,当它似乎没有故障时,它实际上会在inactivityTimeout
到期后发生故障。(所以如果它设置为 10 分钟,那么 10 分钟后它将调用该ChannelFaulted
事件)。 - 我还没有弄清楚为什么在某些情况下它会立即注意到断开连接,而在其他情况下它会等待计时器到期。在这两种情况下,我注意到框架抛出和处理的内部第一次机会通信异常,并且有调用 Abort the connection ......但不知何故,对事件处理程序的调用丢失了,它必须等待超时。我怀疑这与线程有关。
- 在尝试将元数据配置为跨 NetTcp 通道工作时,我得到了零星的结果。有时有效,有时无效。我读过很多报告说元数据不能在 NetTcp 上运行,而且你必须为元数据使用 Http 通道,但实际上我已经多次使用 net.tcp:// url 来生成代理人。然后我会改变一些东西,重新编译它就不再起作用了。改回来,就不行了。因此,让元数据通过 net.tcp 运行,并与同一端口上的端点共享(显然使用不同的地址),需要什么魔法咒语非常令人困惑。
- 在同一服务上同时配置 NetTcp 和 Metatdata 端点,并为连接参数(如 listenBacklog 和 maxConnections)指定非默认设置时,您还需要确保 Metadata 端点使用相同的设置,这通常意味着您必须定义一个自定义绑定,因为这些设置在标准 tcp mex 绑定中不可用。这包括设置
listenBacklog
andmaxPendingConnections
ontcpTransport
和groupName
andmaxOutboundConnectionsPerEndpoint
onconnectionPoolSettings
。 - ReliableSession 的 Ordered 设置的默认设置是
True
. 这比关闭它使用更多的开销。如果您不需要订购的消息,我建议将其关闭(需要在两边都设置)
-
配置我还是需要了解的:
如何正确配置共享 net.tcp 元数据端点?(我会在有机会时添加一个示例)目前,我正在指定一个 http get url 来绕过该问题。为什么它有时有效,有时无效,这与它是如此不一致。在 Visual Studio 中生成代理时,我不断收到错误“无法识别 URI 前缀”。
为什么 WCF 有时会在断开连接后立即对通道进行故障,有时会等待inactivityTimeout
过期?什么控制/导致一种与另一种行为?