The TcpClient class in C# is great for opening a TCP connection, I must say that it's one of the nicest TCP libraries i've used. You just have to watch out for the occasional bug and you'll be right.
One limitation is a frustration though: the inability to set a timeout when opening a connection to a remote server. The default timeout is 60 seconds, which is quite a while to have the user strumming their fingers waiting for things to happen.
My solution to this is to spawn a thread which opens the TCP connection, while the original thread waits up to a user-specified timeout for it to connect. If it hasn't connected by then, it kills the thread and gives up. Notice the use of the thread's Join function which allows the original thread to stop waiting if the connection is quicker than the timeout. Without further ado, the TcpClientWithTimeout.cs class:
using System; using System.Net.Sockets; using System.Threading; /// <summary> /// TcpClientWithTimeout is used to open a TcpClient connection, with a /// user definable connection timeout in milliseconds (1000=1second) /// Use it like this: /// TcpClient connection = new TcpClientWithTimeout('127.0.0.1',80,1000).Connect(); /// </summary> public class TcpClientWithTimeout { protected string _hostname; protected int _port; protected int _timeout_milliseconds; protected TcpClient connection; protected bool connected; protected Exception exception; public TcpClientWithTimeout(string hostname,int port,int timeout_milliseconds) { _hostname = hostname; _port = port; _timeout_milliseconds = timeout_milliseconds; } public TcpClient Connect() { // kick off the thread that tries to connect connected = false; exception = null; Thread thread = new Thread(new ThreadStart(BeginConnect)); thread.IsBackground = true; // So that a failed connection attempt // wont prevent the process from terminating while it does the long timeout thread.Start(); // wait for either the timeout or the thread to finish thread.Join(_timeout_milliseconds); if (connected == true) { // it succeeded, so return the connection thread.Abort(); return connection; } if (exception != null) { // it crashed, so return the exception to the caller thread.Abort(); throw exception; } else { // if it gets here, it timed out, so abort the thread and throw an exception thread.Abort(); string message = string.Format("TcpClient connection to {0}:{1} timed out", _hostname, _port); throw new TimeoutException(message); } } protected void BeginConnect() { try { connection = new TcpClient(_hostname, _port); // record that it succeeded, for the main thread to return to the caller connected = true; } catch (Exception ex) { // record the exception for the main thread to re-throw back to the calling code exception = ex; } } }
And here's a little example of how to use this to open a connection, send 10 bytes, and receive 10 bytes:
// connect with a 5 second timeout on the connection TcpClient connection = new TcpClientWithTimeout("www.google.com", 80, 5000).Connect(); NetworkStream stream = connection.GetStream(); // Send 10 bytes byte[] to_send = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xa}; stream.Write(to_send, 0, to_send.Length); // Receive 10 bytes byte[] readbuf = new byte[10]; // you must allocate space first stream.ReadTimeout = 10000; // 10 second timeout on the read stream.Read(readbuf, 0, 10); // read // Disconnect nicely stream.Close(); // workaround for a .net bug: http://support.microsoft.com/kb/821625 connection.Close();
Cheers all, please let me know if this is useful or if you have any constructive criticism.
Thanks for reading! And if you want to get in touch, I'd love to hear from you: chris.hulbert at gmail.
(Comp Sci, Hons - UTS)
Software Developer (Freelancer / Contractor) in Australia.
I have worked at places such as Google, Cochlear, Assembly Payments, News Corp, Fox Sports, NineMSN, FetchTV, Coles, Woolworths, Trust Bank, and Westpac, among others. If you're looking for help developing an iOS app, drop me a line!
Get in touch:
[email protected]
github.com/chrishulbert
linkedin