使用Task.Wait和Cancel解决Remoting超时Timeout问题

时间:2022-08-23 18:04:50

Remoting客户端用TcpChannel链接服务端的时候,如果地址不存在会尝试连接到超时Timeout大概21秒左右,例如连接到"tcp://192.192.192.192:8080/ServerObject"这个不存在的Remoting service地址。如何才能缩短这个Remoting超时Timeout的时间呢?根据MSDN Channel Properties说明:默认的timeout设置是infinite(无限),默认失败尝试次数/retryCount是一次。所以很自然,设置Remoting客户端用TcpChannel链接服务端的连接超时timeout在timeout参数里面,代码是这样的:

使用Task.Wait和Cancel解决Remoting超时Timeout问题

接下来的代码就是调用instance的方法(IMyServiceContract里面定义的)。

可是测试发现设置的timeout参数没起作用,超时还是21秒。

后来网上搜了一下,的确这是个普遍的问题,看看这个这个帖子,但可惜都没有解决我的问题。网上都没有好的办法,无奈我只好自己搞定了。用.NET 4.0 TPL里面的Task.Wait(timeSpan)和cancel搞定。

使用Task.Wait和Cancel解决Remoting超时Timeout问题

先看看下面的代码:

使用Task.Wait和Cancel解决Remoting超时Timeout问题

我想你一定看懂了,意思就是,线程池启动一个线程,做一些事情(这里假设耗时4秒),但必须在超时时间timeout时间内(这里是3秒)内完成,timeout时间到了就取消该线程任务,并返回false。如果操作在3秒内完成了,那么久返回true。很简单吧。

:这里用了CancelationTokenSource.Cancel()来取消线程任务,并且结合TPL里面的Task.Wait(timeSpan),这样实现timeout时间到了就取消该线程任务。请参考MSDN:Task CancelationHow to: Cancel a Task and Its Children. 细节:如果仅仅调用bool Wait(TimeSpan timeout),时间到了并不会停止任务执行,而是等待任务执行完成,看所用时间如果超过timespan就返回false,否则返回true。)

这个方法就是用来测试一个远程地址是否可用,比如连接到"tcp://192.192.192.192:8080/ServerObject"这个不存在的Remoting service地址,如果能在timeout时间内(例如3秒内)返回,那么测试成功。超过就是失败的服务端地址。可以在上面do some task的地方放置你的耗时操作,例如 Activator.GetObject 或者 instance.dosomething() - 一定要用try-catch括起来哦。

需要注意ChannelServices.UnRegisterChannel

有一点需要注意ChannelServices.UnregisterChannel,如果放在try-catch的那个block里面的话可能不工作,没有效果,看下面的代码:

使用Task.Wait和Cancel解决Remoting超时Timeout问题

原因是如果连接到"tcp://192.192.192.192:8080/ServerObject"这个不存在的Remoting service地址,可能会在Activator.GetObject 或者 instance.dosomething()这一步出现connection failed的异常,提示远程remoting服务器连接不上,然后就走到catch里面调用了ChannelServices.UnregisterChannel了吗?没有,还有retryCount,失败重试,所以实际并没有执行注销channel。

正确的解决方法是在其他地方,或者过一会儿再调用ChannelServices.UnregisterChannel。或者在我上述的函数测试一个远程地址是否可用TestRemotingServerAddress调用完成以后,如果是false,就调ChannelServices.UnregisterChannel。此外,如果endpoint地址改变了,需要调用ChannelServices.UnregisterChannel,否则会发生异常。