C# Socket连接请求超时机制

  • Post author:
  • Post category:其他



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

socket

exception;



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。