WCF客户端在服务停止时忽略超时值

11
我有一个使用WCF的VB .NET应用程序。我已经在代码中为所有客户端超时设置了时间:
    Dim oMastSrv As MastSvc.IclsIOXferClient = Nothing

    Dim binding As New ServiceModel.NetTcpBinding("NetTcpBinding_IclsIOXfer")
    Dim intTimeout As Integer = 2500
    binding.SendTimeout = New TimeSpan(0, 0, 0, 0, intTimeout)
    binding.ReceiveTimeout = New TimeSpan(0, 0, 0, 0, intTimeout)
    binding.OpenTimeout = New TimeSpan(0, 0, 0, 0, intTimeout)
    binding.CloseTimeout = New TimeSpan(0, 0, 0, 0, intTimeout)
    Dim address As New ServiceModel.EndpointAddress("net.tcp://" & GetSrvIP(intSrvID) & ":30000/MyMastSvc")

    oMastSrv = New MastSvc.IclsIOXferClient(binding, address)
    Try
        oMastSrv.ServiceConnect( ... )
        oMastSrv.InnerChannel.OperationTimeout = New TimeSpan(0, 0, 0, 0, intTimeout)
    Catch ex As Exception
        ...
    End Try

当我连接的服务崩溃时,Endpoint Not Found异常需要超过20秒才能被抛出,而不是我指定的2.5秒。这真的会影响我的负载均衡,我需要知道服务在2.5秒内是否消失。有没有办法在期望的时间范围内抛出此异常?
顺便说一下,异常内容类似于:
无法连接到net.tcp://192.168.227.130:30000/MXIOXfer。连接尝试持续了00:00:02.4209684的时间跨度。TCP错误代码10060:由于经过了一段时间后连接方没有正确地响应,或者已建立的连接失败,因为连接的主机未能响应192.168.227.130:30000。
但实际上需要超过20秒。我已经打开了WCF跟踪,并可以看到TCP操作失败警告就在异常之前,并且具有真实时间。
无法连接到 net.tcp://192.168.227.130:30000/MXIOXfer。连接尝试持续了00:00:21.0314092的时间跨度。TCP错误代码10060:连接方在一段时间后未正确响应,或已建立的连接因连接主机未能响应而失败192.168.227.130:30000。
如果有任何区别,所有与服务的通信都在单独的线程上完成。
编辑: 此线程似乎表明套接字超时由操作系统设置。是否有这样的注册表设置?

1
代码示例让OperationTimeout看起来是在通道打开后设置的。如果将其移动到ServiceConnect()之前会发生什么? - ErnieL
@ErnieL - 同样的事情,设置它之前和之后都是一样的。在常规操作中,设置之后需要使超时时间起作用,因此我保留了这个设置。 - MarkFisher
2个回答

3
结合我和eol引用的SO和MSDN社交线程中找到的细节,我得出了以下注册表设置:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces {xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx} \ TcpInitialRTT 值类型:REG_DWORD-数字 有效范围:0-0xFFFF 默认值:3秒 描述:此参数基于每个接口控制用于TCP连接请求和初始数据重传的初始超时。调整此参数时要小心,因为使用指数回退。将此值设置为大于3会导致对不存在的地址进行更长的超时。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces {xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx} \ TcpMaxConnectRetransmissions 值类型:REG_DWORD-数字 有效范围:0-255(十进制) 默认值:2 描述:此参数确定TCP在放弃尝试之前重新传输连接请求(SYN)的次数。在给定的连接尝试中,每次重传时间间隔加倍。初始超时由TcpInitialRtt注册表值控制。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces {xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx} \ TcpMaxDataRetransmissions 值类型:REG_DWORD-数字 有效范围:0-0xFFFFFFFF 默认值:5 描述:此参数控制TCP在中止连接之前重新传输单个数据段(而不是连接请求段)的次数。在连接上,每次重传时间间隔加倍。当响应恢复时,它会重置。重传超时(RTO)值使用每个连接上的历史测量的往返时间(平滑往返时间或SRTT)动态调整。在新连接上的初始RTO由TcpInitialRtt注册表值控制。
由于连接失败时的超时值会使每次重试超时时间翻倍,所以默认值会使第一次尝试3秒失败,第二次尝试6秒失败,第三次和最后一次尝试12秒失败,或总共21秒。顺便说一下,TcpMaxDataRetransmissions键与此无关,我将其包括在内是为了完整性和以后的人们。

默认情况下,这些值都不存在,您需要添加它们以更改它们。确定应该在哪个接口上执行此操作很容易,每个接口都有包含其当前IP地址的键。(甚至有一个用于本地主机)在我的情况下,将TcpMaxConnectRetransmissions设置为零(0),即可将VM接口的套接字超时设置为3秒,这足够接近2.5秒的要求。现在当WCF服务崩溃时,我的负载均衡可以正常工作。


1
做得好,找到了根本原因。给未来的读者一些建议:这是一个低级别的修复方法,可能会影响同一台计算机上的其他程序。最适合用于具有有限用途的机器。此外,我看到一些帖子提到在某些较新版本的Windows中可能已被弃用。马克,请告诉我们您使用的Windows操作系统是哪个版本? - eol
@eol - 当然,我是针对XP->7(.NET 4)的,并且微软的KBA http://support.microsoft.com/kb/170359表示它从NT开始就被支持。有RFC涵盖了这种行为;如果停止支持,微软必须在其他地方提供支持。(依我看,这是第一次处理这个问题的一个糟糕方式。)你能指出表明淘汰的帖子吗? - MarkFisher
1
我一开始就应该这样做。我回去拿那个列表,发现我看到的大约有4个不同地方都说了这句话,但仔细一看,它们都是一个讨论串的克隆/副本(http://social.technet.microsoft.com/Forums/en-US/w7itpronetworking/thread/110271d5-5221-44b4-af14-f07f3fa01a73,在第二个答案下面)。由于只有一个人说了这句话,而我找不到任何其他来源来证实,所以我撤回了关于可能被弃用的说法。 - eol

1

我相信这篇文章讨论的是同样的问题:wcf channelfactory and opentimeout

问题在于底层套接字有一个默认的20秒左右的超时时间,而WCF没有覆盖它。请查看最后一个答案,以了解通过异步打开实现自己的超时的方法。


那个解决方案是用于打开通道的,我的问题是成功打开通道后出现超时但服务崩溃。每次打开通道以确保服务仍在运行会很混乱;当通道已经打开时是否有等效的技术? - MarkFisher
关于这个长时间延迟的另一篇帖子:https://dev59.com/q2025IYBdhLWcg3wf2OE#5989738。看起来套接字层正在搞砸事情。你必须以异步方式执行每个对服务的调用,并自己跟踪超时...至少从我目前发现的情况来看。 - eol

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