WCF各种超时问题的处理


先来引用一下关于超时问题的处理的一些资料


处理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的说明)。

image.png


System.ServiceModel.ClientBase<T>.OperationTimeout

这个是客户端用的,指定等待服务响应的超时时间。这是等待单个操作完成的最长时间。

这个属性只存在于代码中,因为它是工作在代理实例的,配置文件中没有这个。



下图是Wcf的配置工具中设置绑定的属性,其中有我们关注的几种超时属性。

image.png

(图1



image.png

(图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,可以见到超时异常信息。

image.png


解决办法(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" 行不行?

答案是不行,会异常:

image.png

可以这样写:

<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次失败");
        }


image.png


注意我们并不能在超时断线后,再用原来的proxy代理进行重连的。
这是因为WCF的代理实例是基于当前的网络连接状态的,
一旦连接断开,该代理实例就失去了与服务端通信的能力。



(问题2)工中网线被拔掉


对于netTcpBinding,如果用户拔掉网线后,是不是要重新建立新的连接呢?

参考tcp的工作方式,理论应该是下面这样的:

如果拔掉时,恰好没有传输数据,又很快插回去了,这个时候没有达到TCP重传或KeepAlive探测的阈值,
通讯可以继续,不需要重新建立连接。
如果拔掉时,正在传输数据,又很快插回去了,没达到重传的阈值,通讯仍然可以继续。
但是如果持续不把网线插回去,达到了重传的阈值,tcp连接就会中断。
所以问题的关键在于是否tcp会被判定为中断。
中断的判定就是看重传阈值和KeepAlive探测存活的阈值是否超过。

参考:网线被拔掉,tcp连接还在吗?

https://baijiahao.baidu.com/s?id=1726817764132579109&wfr=spider&for=pc




下面用程序来验证:

然鹅~事实打脸了~~

当勇哥禁用虚拟机的网卡后,立刻再启用,再在客户端Add一下,这种情况下应该属于拔了网线时没有传输数据的情况,

但还是报了“套接字连接中止”。


image.png

难道禁用网卡和拔掉网线效果不一样?

我得找两台电脑实际拔网线试下,看是不是也是这个结果。

....

结果试出来了,拔了网线立刻插上,还是报“套接字连接已中止”


用纯tcp通讯方式试一下,结果一拔网线,助手直接报连接中止。

image.png

客户端强行发送,还是失败的。

image.png

看来并不是因为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。

这次终于没有报错了,通讯可以继续!!

image.png

再试下拔下网线后,先点一次Add,然后再插上网线。

结果等了一会后,数据续传了!

image.png

看来靠着“可靠的消息传送”机制,可以防止意外网络中断。

最后的一种情况,拔了网线后,一直不插回去会怎么样呢?

估计到达一个阈值后,会报tcp会话失败。但是这个阈值是多少,就留给有兴趣的朋友去试吧。


然鹅~ 并不是所有的binding都支持“可靠的消息传送”的,具体见图2。



(问题4) 双工通讯中的超时问题


双工通讯中的一种超时错误,是指服务端在回调客户端的时候,如果lsOneWay这个设置不当,会引发一种跟UI相关的超时错误。

不过随着VS变强大,现在这种错误已经看不到了,详细见勇哥这篇文章:

http://47.98.154.65/?id=2431




实验代码下载:

链接:https://pan.baidu.com/s/1kjNElNwe4HeO-9Xyjn5H2A 

提取码:9e67 

--来自百度网盘超级会员V6的分享




另附,测试的时候见到的几种错误,放这里供大家参考。


image.png

解决方法,就是调整服务器端 Binding 的安全方式,比如设为 "None"。


image.png

这个错误,就是可能服务端关闭了安全,客户端配置没有改成一样的。







本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:
本帖最后由 勇哥,很想停止 于 2024-07-02 16:10:02 编辑

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864