public sealed class SocketConnector
{
/// <summary>
/// The wait handle to use to perform the time-out.
/// </summary>
private readonly AutoResetEvent _waitHandle;
/// <summary>
/// The object to perform thread synchronization.
/// </summary>
private readonly object _locker;
/// <summary>
/// The method to invoke on EndConnect.
/// </summary>
private AsyncCallback _callback;
/// <summary>
/// Determines if the <see cref="WaitHandle"/> has been disposed.
/// </summary>
private bool _disposed;
/// <summary>
/// Asynchronously performs a <see cref="Socket.Connect"/> and will return when either the timeout period
/// lapses or the <see cref="Socket"/> has connected.
/// </summary>
/// <param name="socket">The <see cref="Socket"/> to call connect on.</param>
/// <param name="endPoint">The <see cref="EndPoint"/> to connect to.</param>
/// <param name="timeOut">The amount of time to wait for the connect to complete.</param>
/// <param name="state">The object state.</param>
/// <param name="callBack">The method to invoke when the timeout period has lapsed - or - The <see cref="Socket"/> has connected.</param>
public static void AsynchronousConnect(Socket socket, EndPoint endPoint, TimeSpan timeOut, object state, AsyncCallback callBack)
{
new SocketConnector(socket, endPoint, timeOut, state, callBack);
}
/// <summary>
/// Asynchronously performs a <see cref="Socket.Connect"/> and will return when either the timeout period
/// lapses or the <see cref="Socket"/> has connected.
/// </summary>
/// <param name="socket">The <see cref="Socket"/> to call connect on.</param>
/// <param name="endPoint">The <see cref="EndPoint"/> to connect to.</param>
/// <param name="timeOut">The amount of time to wait for the connect to complete.</param>
/// <param name="state">The object state.</param>
/// <param name="callBack">The method to invoke when the timeout period has lapsed - or - The <see cref="Socket"/> has connected.</param>
private SocketConnector(Socket socket, EndPoint endPoint, TimeSpan timeOut, object state, AsyncCallback callBack)
{
if(socket == null)
throw new ArgumentNullException("socket");
if(endPoint == null)
throw new ArgumentNullException("endPoint");
if(callBack == null)
throw new ArgumentNullException("callBack");
_locker = new object();
_disposed = false;
_callback = callBack;
_waitHandle = new AutoResetEvent(false);
try
{
IAsyncResult result = socket.BeginConnect(endPoint, new AsyncCallback(EndConnect), state);
_waitHandle.WaitOne(timeOut, false);
lock(_locker)
{
if(_callback == null)
return;
_disposed = true;
socket.Close();
}
}
finally
{
_waitHandle.Close();
}
}
private void EndConnect(IAsyncResult result)
{
lock(_locker)
{
if(_callback == null)
return;
try
{
_callback.DynamicInvoke(new object[] {result});
}
finally
{
_callback = null;
if(!_disposed)
_waitHandle.Set();
}
}
}
static void Main()
{
handle = new System.Threading.AutoResetEvent(false);
while(true)
{
Console.Write("ENTER IP: ");
string ipAddress = Console.ReadLine();
Console.Write("ENTER PORT: ");
int port = int.Parse(Console.ReadLine());
Console.Write("ENTER TIMEOUT (SECONDS): ");
double timeout = double.Parse(Console.ReadLine());
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endpoint = new IPEndPoint(Dns.Resolve(ipAddress).AddressList[0], port);
handle.Reset();
AsynchronousConnect(socket, endpoint, TimeSpan.FromSeconds(timeout), socket, new AsyncCallback(FIN));
handle.WaitOne();
}
}
static AutoResetEvent handle;
private static void FIN(IAsyncResult result)
{
Socket socket = (Socket) result.AsyncState;
Console.WriteLine(socket.Connected);
socket.Close();
handle.Set();
}
}