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;
tmrCbk = new TimerCallback(timer);
tmr = new Timer(tmrCbk);
tmr.Change(1000, 1000);
#endregion TIMER
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
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
{
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)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
connectTimeout = timeOut;
tmrCbk = new TimerCallback(timer);
tmr = new Timer(tmrCbk);
tmr.Change(1000, 1000);
while (connectTimeout > 0)
{
try
{
socket.Connect(IPHost, port);
tmr.Change(Timeout.Infinite, Timeout.Infinite);
break;
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
}
}
return socket.Connected;
}
finally
{
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.
private static void timer(object state)
{
Console.WriteLine(connectTimeout);
connectTimeout--;
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.