• [译]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。

    总结

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


    [译注]

    作者介绍了一种异步连接+WaitOne的连接请求超时机制。其中的实现细节有值得商榷的地方,比如:a.static成员带来的线程安全性问题;b.可以考虑利用IAsyncResult.AsyncWaitHandle,不必另行创建ManualResetEvent。但瑕不掩瑜,感谢作者的解决思路。

  • 相关阅读:
    怪怪设计论闲谈篇:职责与解耦的矛盾
    知识传播与社区讨论 : 兜售狗皮膏药的"软件先知"
    反弹和补遗:再论Bjarne Stroustrup的"基于对象"的含义
    回帖整理: 领域建模/表模块,Java/.NET 社区风格
    贫血或职责的讨论
    近期可能会研究和讨论的个人动向
    CLR寄宿(上) MSCOREE.DLL
    代码组(2) 成员条件
    说说emit(中)ILGenerator
    CLR寄宿(下) 托管宿主
  • 原文地址:https://www.cnblogs.com/weidagang2046/p/1385977.html
Copyright © 2020-2023  润新知