Execute System.Net.Sockets.Socket.Connect Method with Timeout Controlled by System.Threading.Timer
Connect to remote socket via System.Net.Sockets.Socket.Connect method with timeout controlled by System.Threading.Timer
Introduction
When we need to send messages to a remote host via Socket, we must determine differences between:
- if we want to know the possibility of a connection and
- if we want to actually connect to the remote host.
If we want to know the availability of a remote host, we can use BeginConnect
method from System.Net.Sockets.Socket
class,
which begins an asynchronous request for a remote host connection, otherwise, if we want to establish a connection to the host in order to send data immediately,
we need the Connect
method from the same class.
The purpose of this tip is to show how an asynchronous timeout managed by System.Threading.Timer
works while trying to connect to a remote socket
using System.Net.Sockets.Socket Connect
method.
The need to develop a timeout this way comes up when I needed to send data to a remote host in a synchronous way, I had to check first if the sockets were enabled to receive that data, not only if it were available.
That's why I decided to use the Connect
method instead of the BeginConnect
method. The Connect
method, as can be read in MSDN,
"Establishes a connection to a remote host" while the BeginConnect
method "Begins an asynchronous request for a remote host connection".
By implementing the Connect
method and by controlling the Exceptions
correctly, you can get a synchronous status of your connection with remote socket,
and decide in real time what to do when an error occurs, either keep trying to connect for a certain amount of time or abort the mission.
Using the Code
The code included is divided in three projects: JRINCServerSocket: a server socket simulator, Test_JRINCSocketTimeout: an NUnit test project, and JRINCSocketTimeout: the project that does the job.
To mount the test environment, NUnit for framework 2 needs to be installed in the system in order to run the test project, otherwise you can reference
the JRINCSocketTimeout
from any other project you want and use the methods as shown in test project (Test_JRINCSocketTimeout
) Program.cs class.
JRINCSocketTimeout Project
The JRINCSocketTimeout project has only one class named SocketTimeout.cs which has two methods:
execASYNC method
Executes BeginConnect
method from System.Net.Sockets.Socket
to begin an asynchronous request to the host. An important test you can do is trying to connect to a server that doesn't have a socket listening, in this case the method must return true
because BeginConnect
method is not connecting initially to send data, it only begins the communication which only tell us that the server exists and is available.
public static bool execASYNC(string IPHost, int port, int timeOut)
{
#region TIMER //only for visual purposes
connectTimeout = timeOut;
// Initialize the timer instances and delegates for timer control.
tmrCbk = new TimerCallback(timer);
tmr = new Timer(tmrCbk);
tmr.Change(1000, 1000);
#endregion TIMER
// Creates the socket object.
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// Try to BEGIN an asynchronous request for the remote host connection.
IAsyncResult result = socket.BeginConnect(IPHost, port, null, null);
bool success = result.AsyncWaitHandle.WaitOne(timeOut * 1000, true);
if (!success)
{
socket.Close();
throw new ApplicationException("Failed to connect server.");
}
else
{
// Stops timer by changing interval to infinite
tmr.Change(Timeout.Infinite, Timeout.Infinite);
}
return success;
}
finally
{
socket.Close();
}
}
execByTimer method
Executes Connect
method from System.Net.Sockets.Socket
to establish a connection to a remote host. You can test by trying to connect to a host that doesn't have a socket listening, the returned value must be an error and false when the timer reaches the configured timeout, because the Connect
method is trying to establish a connection constantly until the timer goes out. If you start the simulator before the timer expires, then you would see the application connects to host successfully.
public static bool execByTimer(string IPHost, int port, int timeOut)
{
// Creates the socket object.
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
connectTimeout = timeOut;
// Initialize the timer instances and delegates for timer control.
tmrCbk = new TimerCallback(timer);
tmr = new Timer(tmrCbk);
tmr.Change(1000, 1000);
// While loop checks the connectTimeout variable, which is decreased by timer.
while (connectTimeout > 0)
{
try
{
// Try to ESTABLISH a connection to the remote host.
socket.Connect(IPHost, port);
// Stops timer by changing interval to infinite
tmr.Change(Timeout.Infinite, Timeout.Infinite);
// Breaks the while loop, once connected.
break;
}
// Control SocketExceptions to avoid principal process to stop,
// and retry to connect next time in the while loop.
catch (SocketException se)
{
// Write exception message.
Console.WriteLine(se.ErrorCode + ": " + se.Message);
}
}
// Return final socket state.
return socket.Connected;
}
finally
{
//always close the socket connection.
socket.Close();
}
}
timer method
Is a delegate method executed by System.Threading.Timer
that decreases the timeout variable that represents the timeout of the sync connection.
// Control the timeout variable.
private static void timer(object state)
{
// Writes actual value of connectTimeout.
Console.WriteLine(connectTimeout);
// Decreases connectTimeout variable.
connectTimeout--;
// Checks connectTimeout to stop timer.
if (connectTimeout <= 0)
{
Timer timer = (Timer)state;
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
JRINCServerSocket project
JRINCServerSocket is a WinForms project that emulates a server that enables a socket listener.