Permission is granted to reprint/use these on the web so long as there is a link to my website.

Writing Multi Threaded Code in C# for TCP/IP (2014)

Back to Article Index


Over the last few months I've written an iPhone App for a taxi firm. It connects to a socket server using TCP/IP over 3G and uses a simple message protocol to update status and receive commands. Interestingly, it's not a client server as such but full duplex so the server can send messages to the App or the App can send messages to the server.

The challenges with this project were (a) it was in C#. That was my choice (I hate Objective-C though Swift looks nice) and (b) creating an iPhone App and using TCP/IP over 3G. I used Xamarin which is nice though not cheap. If you haven't come across it, it's Project Mono com

Effectively the iPhone/iOS part doesn't really matter so far as the comms are concerned as the Xamarin ecostructure looks after this. If you've done TCP/IP in C# using the System.Net.Sockets and a TcpClient and NetworkStream then you already know how to do it. Where it did matter was keeping the App responsive and that meant using Threads.

There are two main parts of the App architecture that have to be connected. The first part is the TcpClient and all the communications; the second is the GUI and that's created from a set of buttons that are created at runtime. However before that, let me mention 3G.

Fun with 3G

Compared to the internet, 3G is interesting and has its challenges. Ping times vary enormously and the signal can drop out completely depending on the signal strength, proximity to buildings etc. A taxi is a harsh environment because it's moving a lot. This means the TCP/IP code has to be robust with automatic reconnection. Even more so with an iPhone App as any unhandled exception that reaches iOS kills your App dead.

There's no simple way to know if your TCP/IP connection is still connected or has been dropped. The first you know is when you try to send a message or check to see if any data is there waiting. If either of those generates an exception then the code has to reestablish the connection.

To make an App responsive needs the TCP/IP communications to run in a background thread. I created a simple class with a NetClient and two ConcurrentQueues, one for holding messages to be transmitted and one to hold received messages. In this case the mesage was a byte protocol (the most over used word in the TV series '24'!). Each message is a number of bytes with special byte values to indicate start and end.

    internal class serverMessage
    {
        public List content = new List();
        public int contentLength { get { return content.Count; } }
        public static int _msgid;
        public int msgid { get; set; }

        public byte[] GetBuffer()
        {
            return content.AsEnumerable().ToArray();
        }
		
		...
	}
	
	
	internal class TCPIO {
	    public static TcpClient client;
        public static NetworkStream stream;
        public ConcurrentQueue RxMessages = new ConcurrentQueue(); // these are received
        public ConcurrentQueue TxMessages = new ConcurrentQueue(); // these are sent out	
	
	...
	
	}
	
        /// 
        /// Infinite loop run in a background thread
        /// 
        public void Run()
        {
            while (true)
            {
                if (!TxMessages.IsEmpty)
                {
                    if (TxMessages.TryDequeue(out Support.msg))
                    {
                        SendData();
                    }
                }
                Thread.Sleep(20);
                if (AnyData())
                {
                    var bufferSize = WaitMessage();
                    if (bufferSize > 0)
                    {
                        BuildRxList(bufferSize);
                    }
                }
                Thread.Sleep(80);
            }
        }	
		
		
	internal class TaxiClass {

        public TaxiClass(string hostiP, int _port = 49170)
        {            
            Support.tcpio = new TCPIO(_port,hostiP);
            var myThreadDelegate = new ThreadStart(Support.tcpio.Run);
            t = new Thread(myThreadDelegate) {IsBackground = true};
            t.Start();
        }

    }	
	

The background thread runs a method that is an infinite loop and is started in the TaxiClass constructor. In the Run method it checks to see if there are any messages to send, and if so it dequeues the first one and sends it. It then sleeps for 20 ms and checks to see if there is any data and if so fetches it into a circular buffer and tries to extract a message. If that succeeds then it adds it on the end of the received message queue. After that it sleeps for 80 ms and then loops again, doing this roughly 10 times a second. Most of the time the background thread is sleeping so there's plenty of time for foreground i.e. GUI activities to be responsive.

A timer running in the main GUI thread runs a method ten times a second to see if a message exists in the received message queue and if so it dequeues it and handles it. This makes use of lambda expressions and the task parallels library (TPL) to do processing again for responsiveness. As this can run code using a threadpool thread and some code has to interact with the main GUI it uses InvokeOnMainThread to run that code.

This code below is run in a non GUi thread and determines whether a Nav button can be enabled. It then enables in using a Lambda expression running in the GUI.

   if (NavButton != null)
      NavButton.InvokeOnMainThread(()=> { NavButton.Enabled = true; });

Don't Do This!

The first version that I wrote used TPL to run the code to send messages and look for data. It worked but every 10 or 20 seconds the TCP/IP connection would drop. It was rather dodgy code, because it occasionally used a different thread (from the threadpool) and NetClient can't handle that and the connection was dropped. The current version can maintain TCPIP connections over 3G for several minutes.

The Lesson Is

If you are using an NetClient instance, keep it in the same thread.

 

Back to Article Index

Permission given to reprint/use on the web so long as it includes a link to my website.
If you like this article, share it by bookmarking- click an icon below

Bookmark C# Multithreaded code for TCP/IP at del.icio.us    Digg C# Multithreaded code for TCP/IP at Digg.com    Bookmark C# Multithreaded code for TCP/IP at Reddit.com    Bookmark C# Multithreaded code for TCP/IP at Spurl.net    Bookmark C# Multithreaded code for TCP/IP at Simpy.com    Bookmark C# Multithreaded code for TCP/IP at NewsVine    Blink this C# Multithreaded code for TCP/IP at blinklist.com    Bookmark C# Multithreaded code for TCP/IP at Furl.net    Fark C# Multithreaded code for TCP/IP at Fark.com    Bookmark C# Multithreaded code for TCP/IP at YahooMyWeb