介绍

您可能注意到了,.Net的System.Net.Sockets.TcpClient和System.Net.Sockets.Socket都没有直接为Connect/BeginConnect提供超时控制机制。因此,当服务器未处于监听状态,或者发生网络故障时,客户端连接请求会被迫等待很长一段时间,直到抛出异常。默认的等待时间长达20~30s。.Net Socket库的SocketOptionName.SendTimeout提供了控制发送数据的超时时间,但并非本文讨论的连接请求的超时时间。

背景

这个问题最初源于我的某个项目,在解决以后,我曾将关键代码发表在自己的博客上。我注意到不少人对此表示感谢,所以我想这是一个常见的问题,或许很多人都需要解决它。

实现

下面是实现的关键代码:

class TimeOutSocket
{
private static bool IsConnectionSuccessful = false;
private static Exception socketexception;
private static ManualResetEvent TimeoutObject = new ManualResetEvent(false); public static TcpClient Connect(IPEndPoint remoteEndPoint, int timeoutMSec)
{
TimeoutObject.Reset();
socketexception = null; string serverip = Convert.ToString(remoteEndPoint.Address);
int serverport = remoteEndPoint.Port;
TcpClient tcpclient = new TcpClient(); tcpclient.BeginConnect(serverip, serverport,
new AsyncCallback(CallBackMethod), tcpclient); if (TimeoutObject.WaitOne(timeoutMSec, false))
{
if (IsConnectionSuccessful)
{
return tcpclient;
}
else
{
throw socketexception;
}
}
else
{
tcpclient.Close();
throw new TimeoutException("TimeOut Exception");
}
}
private static void CallBackMethod(IAsyncResult asyncresult)
{
try
{
IsConnectionSuccessful = false;
TcpClient tcpclient = asyncresult.AsyncState as TcpClient; if (tcpclient.Client != null)
{
tcpclient.EndConnect(asyncresult);
IsConnectionSuccessful = true;
}
}
catch (Exception ex)
{
IsConnectionSuccessful = false;
socketexception = ex;
}
finally
{
TimeoutObject.Set();
}
}
}

这里,ManualResetEvent的WaitOne(TimeSpan, Boolean)起到了主要的作用。它将阻止当前线程,直到ManualResetEvent对象被Set或者超过timeout时间。上面的代码中,调用BeginConnect后通过WaitOne方法阻止当前线程,如果在timeoutMSec时间内连接成功,将在CallBackMethod回调中调用TimeoutObject.Set,解除被阻塞的连接线程并返回;否则,连接线程会在等待超时后,主动关闭连接并抛出TimeoutException。

最新文章

  1. PDF 补丁丁 0.5.0.1816 测试版发布:新界面新体验
  2. 兼容性测试-如何使用IE11做低版本IE的兼容性测试
  3. thinkphp 3.23 第三方登录sdk集成包
  4. Tomcat6.0的Thisisverylikelytocreateamemoryleak异常
  5. timus 1106 Two Teams(二部图)
  6. VC编译连接选项详解(转)
  7. Android学习笔记(2)
  8. Asp.net web服务处理程序(第六篇)
  9. 这 5 个前端组件库,可以让你放弃 jQuery UI
  10. centos7多网卡配置bond0 (mode6无需交换机做配置)
  11. 20. Valid Parentheses ★
  12. 生成uuid唯一标识符
  13. vue安装调试器Vue.js devtools
  14. Android dimen
  15. python 多进程的启动和代码执行顺序
  16. CMMI之功能点估算法---内部逻辑文件和外部接口文件
  17. jQery的方法
  18. 基于 Tornado 实现的 Web 站点反向代理
  19. Java 中的类
  20. 使用JavaMelody监控tomcat以及jvm

热门文章

  1. qfish/Bee-Xcode-Template
  2. This template requires a more recent version of the Android Eclipse plugin. Please update from versi
  3. Centos下zabbix部署(二)agent安装并设置监控
  4. C#的Convert.FromBase64String
  5. [BZOJ4756][Usaco2017 Jan]Promotion Counting 树状数组
  6. 关于引用iframe的一点小说明
  7. 牛客网 牛客小白月赛5 I.区间 (interval)-线段树 or 差分数组?
  8. Python与数据库[2] -> 关系对象映射/ORM[3] -> sqlalchemy 的声明层 ORM 访问方式
  9. BZOJ 2669- [cqoi2012]局部极小值
  10. Oracle多用户对一个表进行并发插入数据行操作