As previously noted in an article posted by Razan Paul, there is a rather lengthy timeout in WinSock before a synchronous Connect using
System.Net.Sockets.TcpClient fails. This can lead to rather lengthy waits (up to 30 seconds) if you attempt to connect to a service that is not available due to a filtering mechanism in your path (firewall).
I could have never gotten this far without first reading over how Razan had done this. Many thanks to him for this article.
Recently, I've been working on several projects that require knowing whether a service is available. Most of us have written Ping applications that track if a device is up, but in this instance, I needed to make sure the port was responding to a TCP Socket before calling some other functions that do various and lengthy subroutines before returning their result. To get past this, I had chosen to use the asynchronous
BeginConnect function provided in the
Sockets.TcpClient class and just threaded out the processes to manage the long wait times that could occur. This turned out to be rather ugly code-wise, and not very efficient, resulting in a rather ridiculous amount of exception catching.
To resolve the issue, I wrote a rather small
static function that interacts similar to the PortQry or NMap tools. We simply attempt to connect using the
BeginConnect Subroutine, and then wait until our timeout has occurred at which we assume the port is no longer responding and mark it filtered. Not only is this extremely responsive, but it threads really well when used in a
Using the Code
The following has the basic implementation for the function:
public static SocketResponse SocketPoll(string Node ,
int tcpPort ,
int tcpTimeout )
if (Node == null || Node.Trim() == "") Node = "127.0.0.1";
if (tcpPort < 0) tcpPort = 135;
if (tcpTimeout < 0) tcpPort = 2500;
IPAddress ipNode = DetermineIP(Node);
TcpClient tSocket = new TcpClient();
DateTime endTime = DateTime.Now.AddMilliseconds(tcpTimeout);
IAsyncResult ar = tSocket.BeginConnect(ipNode, tcpPort, null, tSocket);
null in the previous bit of code. I chose to NOT utilize the
CallBack as I'm not concerned with any cleanup until we get back to the primary bit of code. We're really treating this as a synchronous function, and terminating the request if the function doesn't complete in the time we have allotted.
Should you want to do something with the open connection once it's completed, you could write a Callback Function that accepts an
AsyncCallback, does something with the
IAsyncResult and returns to the calling function. I started with this method, and realized how incredible of a task reimplementing the
IAsyncResult interface and
AsyncCallback delegates were going to be.
while(DateTime.Now < endTime)
Socket s = tSocket.Client;
if (!s.Poll(100, SelectMode.SelectError))
TcpClient.Client exposes the
Socket class that
TcpClient was built on top of, allowing us to use
Socket.Poll to get the
SocketError (ICMP response) should the attempt fail.
In the event that we connect successfully, poll fails, and we return the
catch (System.Net.Sockets.SocketException SocketEx)
default: return SocketResponse.OTHER;
In the event that ICMP actually responds, signifying the TCP Port isn't filtered with a firewall,
Poll(100, SelectMode.SelectError) throws the
SocketException associated with the received ICMP message.
So, finally if a TCP connection hasn't been established or an exception hasn't been thrown due to receipt of an ICMP message indicating a failed connection, the thread sleeps for 10 milliseconds allowing other threads to execute in the mean time, and we start over until the timeout is exceeded.
At the point the timeout is exceeded, we simply return the
FILTERED SocketException back to the calling function.
Points of Interest
Raw Sockets are no longer supported post Windows XP Service Pack 3. Wonderful.
- 4th June, 2010: Initial post