zoukankan      html  css  js  c++  java
  • C# Socket连接请求超时机制

    作者:RazanPaul

    译者:Todd Wei

    原文:http://www.codeproject.com/KB/IP/TimeOutSocket.aspx

    介绍

    您可能注意到了,.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。

     

     

    总结

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

  • 相关阅读:
    oracle 导入数据时提示只有 DBA 才能导入由其他 DBA 导出的文件
    oracle 常用语句
    android udp 无法收到数据 (模拟器中)
    android DatagramSocket send 发送数据出错
    AtCoder ABC 128E Roadwork
    AtCoder ABC 128D equeue
    AtCoder ABC 127F Absolute Minima
    AtCoder ABC 127E Cell Distance
    CodeForces 1166E The LCMs Must be Large
    CodeForces 1166D Cute Sequences
  • 原文地址:https://www.cnblogs.com/adjk/p/4217546.html
Copyright © 2011-2022 走看看