先来引用一下关于超时问题的处理的一些资料
处理WCF超时的最佳方法
1. 调整WCF绑定配置:可以通过修改绑定配置来增加或减少超时时间。
在WCF配置文件中,可以设置连接超时、读取超时和发送超时等参数。根据具体情况,
可以适当增加这些超时时间,以确保请求能够在预定时间内完成。
2. 使用异步操作:使用异步操作可以提高WCF服务的性能和响应能力。
通过使用异步操作,可以将长时间运行的操作放在后台线程中进行处理,从而避免阻塞主线程。
这样可以减少超时错误的发生。
3. 实现心跳机制:通过定期发送心跳消息,可以保持WCF服务和客户端之间的连接活跃。
如果在一段时间内没有收到心跳消息,可以认为连接已经断开,并采取相应的处理措施,如重新连接或关闭连接。
4. 使用断线重连机制:在网络不稳定的情况下,可能会出现连接断开的情况。
为了应对这种情况,可以实现断线重连机制。当检测到连接断开时,可以自动重新连接,并继续之前的操作。
5. 使用故障转移和负载均衡:通过使用故障转移和负载均衡技术,可以将请求分发到多个WCF服务实例上
,从而提高系统的可用性和性能。当某个服务实例出现故障或超时时,可以自动切换到其他可用的服务实例。
总结起来,处理WCF超时的最佳方法包括调整绑定配置、使用异步操作、实现心跳机制、
使用断线重连机制以及使用故障转移和负载均衡技术。这些方法可以提高WCF服务的可靠性、性能和响应能力。
WCF通讯经常出现超时问题
第一种超时问题:
客户端与服务端建立连接的时候如果没有设定参数,默认客户端在10分钟内没有与服务端通讯,则连接会断开,提示连接超时问题
解决方法一:
客户端保留连接信息,使用tny catch语句捕获异常,在catch语句中重新与服务端建立连接
解决方案二:
客户端在建立连接的时候就设定参数,但是长连接也会占用系统性能,视连接数量而定,保持太多连接没有什么好处
param.CloseTimeout=TimeSpan.MaxValue;
param.ReceiveTimeout=TimeSpan.MaxValue;
param.SendTimeout=TimeSpan.MaxValue;
param.OpenTimeout=TimeSpan.MaxValue;
param.BindingMaxBufferSize=int.MaxValue;
param.BindingMaxReceivedMessageSize=int.MaxValue;
第二种超时问题:
服务端在回调客户端的时候,如果lsOneWay=True,同步回调,默认情况下1分钟后会提示回调超时,
一般这种情况是由于服务端挂在UI线程中,当你执行回调的时候U!线程就卡住了,
一直处于等待返回的状态,而这个时候即使客户端回调返回,
挂在U!线程中的服务端也不会收到通知,直到超时
"发送到 hto:/schemas.microsoft.com/2005/12/ServiceModelAddressing/Anonymous
的请求操作在配置的超时(00:00:59.9969999)内未收到回复。
分配给此操作的时间可能已经是更长超时的一部分。这可能由于服务仍在处理操作或服务无法发送回复消息。
请考虑增加操作超时(将通道/代理转换为·并设置 OperationTimeout 属性)并确保服务能够连接到客户端。"
解决方法就是,把服务端的回调放在线程中,并通过事件通知客户端返回结果。如果是循环回调的话,
可以在事件中再次调用这个循环方法,而循环在回调处就退出,用事件来触发循环
详解一下各种超时参数
下面几种超时都属于wcf配置工具里的“绑定”项目的属性,包括:
CloseTimeout
默认时长 :00:01:00
定义允许服务正常关闭所需的最长时间。该时间限制一过,系统会强制关闭服务。
OpenTimeout
默认时长:00:01:00
定义允许服务正常打开所需的最长时间。该时间限制一过,系统会强制关闭服务
ReceiveTimeout
默认时长:00:10:00
为完成接收操作提供的时间间隔
SendTimeout
默认时长:00:01:00
为完成发送操作提供的时间间隔
InactivityTimeout
默认时长:00:10:00
这个参数用于在启用可靠会话(Reliable Sessions)时,控制会话在多长时间内没有活动(即没有发送或接收消息)
后会被关闭。虽然它直接影响的是会话的保持时间,但也可以看作是控制“无通讯则断开”行为的一个参数。
注意,这个参数是可选的,且只在启用了可靠会话的情况下有效,即下图的Enabled为true时才有意义。
但不是每个binding类型都是支持可靠的会话的(见图2的说明)。
System.ServiceModel.ClientBase<T>.OperationTimeout
这个是客户端用的,指定等待服务响应的超时时间。这是等待单个操作完成的最长时间。
这个属性只存在于代码中,因为它是工作在代理实例的,配置文件中没有这个。
下图是Wcf的配置工具中设置绑定的属性,其中有我们关注的几种超时属性。
(图1
(图2)常用binding类型的特性。
网传的解决10分钟超时的方式
通过后面的实际代码测试,貌似是有问题的。
直接设置receiveTimeout属性是没作用的,另外直接设置inactivityTimeout属性,也不会起作用。
我们可以在MSDN找到官方解释:
使用可靠会话时,必须同时满足两个不同的非活动计时器,才能使连接处于活动状态。 如果任一非活动计时器结束计时,则将断开连接。 第一个非活动计时器为可靠会话计时器,称为 InactivityTimeout。 如果在超时期限内没有收到任何应用程序消息或基础结构消息,此非活动计时器将激发。 基础结构消息是指为了通道堆栈中的协议之一(例如,保持活动状态或确认,而并非包含应用程序数据)而生成的消息。 第二个非活动计时器为服务计时器,它使用绑定的 ReceiveTimeout 设置。 如果在超时期限内没有收到任何应用程序消息,此非活动计时器将激发。 例如,它可以指定服务器关闭会话所用的通道前,客户端向服务器发送至少一个消息所需的最长时间。 此行为确保了客户端不能无限期地占用服务器资源。 所以我们必须同时设置这两个属性,例如: <binding name="tcpBinding" maxReceivedMessageSize="2147483647" transferMode="Buffered" receiveTimeout="24.00:00:00"> <reliableSession inactivityTimeout="24.00:00:00" /> </binding>
代码测试和解决方案
勇哥先提供基础代码,方便大家。
链接:https://pan.baidu.com/s/1_oSET4tN54EDHugf7vxM_Q
提取码:36my
--来自百度网盘超级会员V6的分享
(问题1)10分钟不操作,连接会断开
服务端binding是netTcpBinding
Add一次后,等10分钟后再次Add,可以见到超时异常信息。
解决办法(1)修改receiveTimeout
经实验,只需要修改receiveTimeout就可以了。下面是改为24小时不断线。
并不需要同时修改inactivityTimeout。
<bindings> <netTcpBinding> <binding name="NewBinding0" receiveTimeout="24:00:00"> <!--<reliableSession inactivityTimeout="00:01:00" enabled="true" />--> </binding> </netTcpBinding> </bindings>
如果你想把receiveTimeout="200:00:00" 行不行?
答案是不行,会异常:
可以这样写:
<binding name="NewBinding0" receiveTimeout="24.00:01:00">
表示24天0小时1分0秒
但是你不能超出24天。
解决办法(2)心跳包
这个办法简单有效。
在服务端加一个简单的函数
public void Heart(int k)
{
heartjs = k;
}
客户端弄个定时器,隔一定时间调用一次
private void timer1_Tick(object sender, EventArgs e)
{
proxy.Heart(1);
}
解决办法(3)超时断线重连
如果超时我们就new一个新的proxy,下面是循环3次,可以重试2次。
private void button1_Click(object sender, EventArgs e) { for (int i = 0; i < 3; i++) { try { OutMsg($"{proxy.Add(1, 1).ToString()} {DateTime.Now.ToString()}"); return; } catch (Exception ex) { //MessageBox.Show(ex.Message); OutMsg(ex.Message); proxy = new calfun.CalculatorServiceClient(); } } OutMsg("重试连接3次失败"); }
注意我们并不能在超时断线后,再用原来的proxy代理进行重连的。
这是因为WCF的代理实例是基于当前的网络连接状态的,
一旦连接断开,该代理实例就失去了与服务端通信的能力。
(问题2)工作中网线被拔掉
对于netTcpBinding,如果用户拔掉网线后,是不是要重新建立新的连接呢?
参考tcp的工作方式,理论应该是下面这样的:
如果拔掉时,恰好没有传输数据,又很快插回去了,这个时候没有达到TCP重传或KeepAlive探测的阈值, 通讯可以继续,不需要重新建立连接。 如果拔掉时,正在传输数据,又很快插回去了,没达到重传的阈值,通讯仍然可以继续。 但是如果持续不把网线插回去,达到了重传的阈值,tcp连接就会中断。 所以问题的关键在于是否tcp会被判定为中断。 中断的判定就是看重传阈值和KeepAlive探测存活的阈值是否超过。
参考:网线被拔掉,tcp连接还在吗?
https://baijiahao.baidu.com/s?id=1726817764132579109&wfr=spider&for=pc
下面用程序来验证:
然鹅~事实打脸了~~
当勇哥禁用虚拟机的网卡后,立刻再启用,再在客户端Add一下,这种情况下应该属于拔了网线时没有传输数据的情况,
但还是报了“套接字连接中止”。
难道禁用网卡和拔掉网线效果不一样?
我得找两台电脑实际拔网线试下,看是不是也是这个结果。
....
结果试出来了,拔了网线立刻插上,还是报“套接字连接已中止”
用纯tcp通讯方式试一下,结果一拔网线,助手直接报连接中止。
客户端强行发送,还是失败的。
看来并不是因为wcf的netTcpBinding对Tcp进行了属于自己的改造。
而是勇哥对于tcp拔网线这个知识点跟现实脱节了。
有网友留言说拔网线这种情况下,网卡会发出一个硬件中断,系统立刻知晓。看上去好像真是这样的。
解决方法:
必须重新启用一个新的连接来继续通讯。
重试指定次数。
那么如果启用了wcf的可靠的消息传送,会怎么样呢?
(问题3) 可靠的消息传送
先启用可靠的会话。
<reliableSession enabled="true" />
<netTcpBinding> <binding name="NewBinding0" receiveTimeout="00:01:00"> <reliableSession enabled="true" /> <security mode="None" /> </binding> </netTcpBinding>
再拔网线,立刻插上,然后Add。
这次终于没有报错了,通讯可以继续!!
再试下拔下网线后,先点一次Add,然后再插上网线。
结果等了一会后,数据续传了!
看来靠着“可靠的消息传送”机制,可以防止意外网络中断。
最后的一种情况,拔了网线后,一直不插回去会怎么样呢?
估计到达一个阈值后,会报tcp会话失败。但是这个阈值是多少,就留给有兴趣的朋友去试吧。
然鹅~ 并不是所有的binding都支持“可靠的消息传送”的,具体见图2。
(问题4) 双工通讯中的超时问题
双工通讯中的一种超时错误,是指服务端在回调客户端的时候,如果lsOneWay这个设置不当,会引发一种跟UI相关的超时错误。
不过随着VS变强大,现在这种错误已经看不到了,详细见勇哥这篇文章:
实验代码下载:
链接:https://pan.baidu.com/s/1kjNElNwe4HeO-9Xyjn5H2A
提取码:9e67
--来自百度网盘超级会员V6的分享
另附,测试的时候见到的几种错误,放这里供大家参考。
解决方法,就是调整服务器端 Binding 的安全方式,比如设为 "None"。
这个错误,就是可能服务端关闭了安全,客户端配置没有改成一样的。

