Lockup during Connect()

Apr 16, 2014

If you try to connect to a host on the network that doesn't exist, or just isn't responding, your thread will lock up until the host responses (which may be never).

Although the .Net Framework theoretically handles all of this with no problem, the 4.2 version of the .Net Micro Framework is missing a number of important properties and methods.

According to the documentation the normal way to handle this situation is to set the Blocking socket option to false, then the Connect() method will throw an exception because it can't connect immediately (the TCP connect protocol takes some time).  You catch the exception and wait for the connection to be completed, and if it doesn't complete quickly enough then you return an error.  No hang.

Unfortunately, the 4.2 .Net Micro Framework is missing the Blocking and Connected properties, and the Send() method does not work as documented.  The following code shows how to get around this ... but it's a bit of a kludge.

using System.Net.Sockets;
using System.Reflection;

int TIME_PORT = 37;
IPEndPoint iep = new IPEndPoint(
    IPAddress.Parse("192.168.3.3"), TIME_PORT);
Socket socket = new Socket(AddressFamily.InterNetwork,
    SocketType.Stream, ProtocolType.Tcp);

Type sType = Type.GetType("System.Net.Sockets.Socket");
FieldInfo blockingInfo = sType.GetField("m_fBlocking",
    BindingFlags.NonPublic | BindingFlags.Instance);
blockingInfo.SetValue(socket, false);

try {
    socket.Connect(iep);
} catch (SocketException se) {
    // Ignore this exception, it takes time to complete the connection.
}

This code uses reflection to access the blocking property which is not publicly available to us.  It catches the exception during Connect() and ignores it.

The problem is how to we know if the connect completes? The documentation says that you should get an exception if  you call Send() with a zero length and  the socket hasn't finished connecting, but it doesn't.  If you call Send() with a non-zero length then it hangs whether blocking is true or false.  And if you call Receive() it just returns 0 bytes.

The good news is that the SendTimeout property does work.  If you set it to 300 the send will wait for 300 milliseconds and then throw an exception (might as well set the ReceiveTimeout value to 300 too).

So add the following code and you should be good to go.  There is a slight chance that you'll need to wait a little bit for the connection to complete, or maybe retry the first send a few times before giving up.

socket.SendTimeout = 300;
socket.ReceiveTimeout = 300;

byte[] cmd = new byte[1];
try {
    int xx = socket.Send(cmd, 1, SocketFlags.None);
} catch (SocketException se) {
    // Unable to send data - probably no connection.
}

 

Source: John Lyman



Category: Reference

John Lyman

Please add your bio info through your member profile page, or through your dashboard.


Add Pingback

Please add a comment

You must be logged in to leave a reply. Login »