DotNet · 2011年3月17日

异步连接-设定超时

介绍

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

实现

下面是实现的关键代码:

  1. class
    TimeOutSocket
  2. {
  3.  
      private static bool IsConnectionSuccessful = false;
  4.  
      private static Exception socketexception;
  5.  
      private static ManualResetEvent TimeoutObject = new
    ManualResetEvent(false);

  6.  
      public static TcpClient Connect(IPEndPoint remoteEndPoint, int
    timeoutMSec)
  7.  
      {
  8.  
          TimeoutObject.Reset();
  9.  
          socketexception = null;  

  10.  
          string serverip =
    Convert.ToString(remoteEndPoint.Address);
  11.  
          int serverport = remoteEndPoint.Port;     
        
  12.  
          TcpClient tcpclient = new TcpClient();
  13.  
          
  14.  
          tcpclient.BeginConnect(serverip, serverport, 
  15.  
              new AsyncCallback(CallBackMethod),
    tcpclient);

  16.  
          if (TimeoutObject.WaitOne(timeoutMSec, false))
  17.  
          {
  18.  
              if (IsConnectionSuccessful)
  19.  
              {
  20.  
                  return tcpclient;
  21.  
              }
  22.  
              else
  23.  
              {
  24.  
                  throw socketexception;
  25.  
              }
  26.  
          }
  27.  
          else
  28.  
          {
  29.  
              tcpclient.Close();
  30.  
              throw new TimeoutException(“TimeOut
    Exception”);
  31.  
          }
  32.  
      }
  33.  
      private static void CallBackMethod(IAsyncResult asyncresult)
  34.  
      {
  35.  
          try
  36.  
          {
  37.  
              IsConnectionSuccessful = false;
  38.  
              TcpClient tcpclient =
    asyncresult.AsyncState as TcpClient;
  39.  
              
  40.  
              if (tcpclient.Client != null)
  41.  
              {
  42.  
                 
    tcpclient.EndConnect(asyncresult);
  43.  
                  IsConnectionSuccessful =
    true;
  44.  
              }
  45.  
          }
  46.  
          catch (Exception ex)
  47.  
          {
  48.  
              IsConnectionSuccessful = false;
  49.  
              socketexception = ex;
  50.  
          }
  51.  
          finally
  52.  
          {
  53.  
              TimeoutObject.Set();
  54.  
          }
  55.  
      }
  56. }

复制代码

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

总结

虽然实现非常简单,但或许很多人都需要连接请求超时机制,如果有任何问题,我会尽力为您解答。

最新电影,电视剧,尽在午夜剧场

电影电视剧午夜不寂寞