Extending .NET

This article was originally published in VSJ, which is now part of Developer Fusion.
The .NET framework contains a lot of functionality that can be used to make even simple tasks easier – but sometimes finding the right pieces to put together isn’t as straightforward as it should be. A recent project required me to develop a Windows Forms application capable of using a fairly old (and proprietary) network protocol to post a modified version of a file to a server.

The protocol in question is based on the Telnet protocol. Telnet is a protocol for transferring character data over a TCP connection, and it defines a number of control characters (e.g. for carriage return and line feed). FTP works in “line” mode, which is to say that the server will always send a whole line of text at a time, and will not start to interpret data it receives until the whole line has been received. Sound familiar? It should. Many other protocols in common use today work in a similar way, including FTP, POP3, and SMTP.

The key building block is therefore a class that allows us to send and receive text over a TCP connection, a line at a time. Let’s call it LineTextProtocol. The .NET Socket class is the obvious place to start, and will handle the connection from a byte-transfer perspective. In this application however, we actually want to send and receive strings. True to form, the .NET framework has classes to help us with this task also, in the form of the StreamReader and StreamWriter classes, which provide a mechanism for converting between strings and a byte stream. These classes communicate with an underlying object-derived Stream, and a quick inspection of the documentation quickly reveals that Socket does not inherit from Stream. Further exploration of the documentation shows that there is a NetworkStream class that can be layered on top of a Socket and provides a Stream interface to it that can be used to attach the StreamReader and StreamWriter classses. This results in the stack of .NET classes shown in Figure 1.

Figure 1
Figure 1: Layering of .NET objects

Since the application is forms-based, it is important that the FTP implementation allows all control and transfer traffic to take place either in an asynchronous fashion. If we were using the Socket class directly, we could take advantage of its own asynchronous features. StreamWriter doesn’t have any asynchronous functions, but in fact data written through a synchronous function call to “WriteLine” will be transmitted asynchronously by the underlying objects, device drivers and hardware. In fact, there is no way to tell when the data has actually been sent, only when the transmit buffer at .NET level is empty. The StreamReader class doesn’t have any asynchronous functions either.

Since we don’t get asynchronous support from the .NET framework, we’ll have to build it ourselves. An implementation using a separate thread is one solution, and it’s the technique I’ve usually used in the past with MFC. The threading support in the .NET framework looks excellent on paper, and this seemed like a good chance to put it to the test.

There is one more thing we must take into account before proceeding with the design. If you examine the documentation for the Socket class closely (and in fact all of the others in the stack) you will find the following statement.

“Any public static (Shared in Visual Basic) members of this type are safe for multithreaded operations. Any instance members are not guaranteed to be thread safe”

Since the objects we are using are not thread safe, the simplest way to ensure no concurrent access is that all of the calls we make into them take place on the thread we create. We’ll need a synchronised object to send data from the application thread (that calls the Write function on the object) to our own thread. There was a time when such considerations were often ignored, and most of the time things worked OK because the system only had a single CPU anyway. With the advent of HyperThreading versions of the Pentium IV processor, making multithreaded software safe is more of a concern than ever before!

We’ve established the objects required, and the listing below shows the code used to declare the relevant objects and initialise them.

internal class LineTextProtocol : IDisposable
{
	private Socket m_Socket = null;
	private NetworkStream m_NetworkStream = null;
	private StreamReader m_StreamReader = null;
	private StreamWriter m_StreamWriter = null;
	private Thread m_Thread = null;

	private ArrayList m_SendList = null;

	public LineTextProtocol(System.Net.EndPoint ep)
	{
		m_Socket = new Socket(ep.AddressFamily,
		SocketType.Stream , ProtocolType.Tcp);
		m_Socket.SetSocketOption(SocketOptionLevel.Socket,
			SocketOptionName.ReceiveTimeout, 10);
		m_Socket.Connect( ep );
		m_NetworkStream = new NetworkStream(m_Socket ,
			FileAccess.ReadWrite , false );
		m_StreamWriter = new StreamWriter( m_NetworkStream ,
			System.Text.Encoding.ASCII );
		m_StreamReader = new StreamReader( m_NetworkStream,
			System.Text.Encoding.ASCII );
		m_SendList = ArrayList.Synchronized(new ArrayList() );
		m_Thread = new Thread(new ThreadStart( ProtocolThread ) );
	}

	public void SendString( string Send )
	{
		m_SendList.Add( Send );
	}
The code above creates and initialises the new thread, but doesn’t actually start it. This is because we need to allow time for the “client” of this class to attach to the events before we start the thread, otherwise the application could miss events that happen immediately – and hence miss important data. Another consideration introduced by using a second thread is that any exceptions on the second thread will be handled on it. This means that the application doesn’t get a chance to see them. The approach chosen here is that if an exception that cannot be handled on the thread occurs, it will throw the exception out as an event before terminating. The listing below shows an additional public function to start the thread, and the events supported by our wrapper.
	public void Start()
	{
		m_Thread.Start();
	}

	public delegate void StringEventHandler(object sender , string s );
	public event StringEventHandler SentStringEvent	;
	public event StringEventHandler ReceivedStringEvent;
	public delegate void DisconnectedEventHandler(object sender );
	public event DisconnectedEventHandler DisconnectedEvent;
	public delegate void ProtocolExceptionEventHandler(
		object sender , Exception e );
	public event ProtocolExceptionEventHandler ProtocolExceptionEvent;
Having established a means of getting the object constructed and started, the next important thing to consider is how to stop it again at the end of its lifetime. There are a few important considerations here. Since we’re using an OS resources (the network socket and the thread) we implement the IDisposable interface to allow the application to relinquish these resources. However, we must not access any of the member variables when the object is called from a finalizer. The code shown below follows the recommended pattern for implementing disposal logic (note that since there are no unmanaged resources owned by this class, no real work is done by the Finalizer.).
	bool m_Disposed = false;
	public void Dispose()
	{
		Dispose( true );
		GC.SuppressFinalize( this );
	}

	protected virtual void Dispose( bool disposing )
	{
		if ( !m_Disposed )
		{
			m_Disposed = true;

			// Dispose managed resources here if
			// there are any - always executed
			if ( disposing )
			{
				// Dispose unmanaged resources here -
				// only executed from Dispose, not from the Finalizer
				if ( m_Thread != null )
				{
					m_Thread.Abort();
					m_Thread.Join();
				}
				if ( m_Socket != null )
				{
					m_Socket.Close();
				}
				if ( m_NetworkStream != null )
				{
					m_NetworkStream.Close();
				}
				if ( m_StreamReader != null )
				{
					m_StreamReader.Close();
				}
				if ( m_StreamWriter != null )
				{
					m_StreamWriter.Close();
				}
			}
		}
	}

	~LineTextProtocol()
	{
		Dispose(false);
	}
Having put in place the framework for the LineTextProtocol class, there is one task remaining to complete it, and that is writing the thread function previously referred to, ProtocolThread in the source code. This throws up a number of new complexities. Firstly, since there is no asynchronous version of the ReadLine function on the StreamReader, we must call it synchronously. However, it is possible that we may wish to send a string to the server but it does not wish to send one to us. If we are blocked in the ReadLine function, then we can’t send the string. The solution to this is to set a really short timeout on the Socket so that the ReadLine function fails quickly with a timeout exception when no data is available. This allows us to write out any waiting data, and the try the ReadLine function again.

The second complexity we must deal with is exception handling. The timeout on the ReadLine function will cause an exception that must be distinguished from other faults using the InnerException property of the exception and Win32 error codes. If the caught exception is not a timeout that can be ignored, we re-throw the exception. The main exception handler notifies disconnection if appropriate or alternatively passes the exception on to the application using the appropriate event handler. Since this exception handling mechanism is in place already, it is used to handle all disconnections, and in fact the main loop continues until an exception takes place – there is no other way out of it. In .NET the exception is not a terrible event reserved for fatal error conditions. It is simply a mechanism for reporting some exception to normal operation.

The code for the thread function is shown below.

	private void ProtocolThread()
	{
		string receivedString = null;
		try
		{
			while ( true )
			{
				if ( !m_Socket.Connected )
				{
				// Throw an exception to avoid reading more data and to flag
				// disconnection (whether intended or not)
					throw new Exception("Should Never Propogate...");
				}
				try
				{
					while ( ( receivedString = m_StreamReader.ReadLine() ) != null )
					{
						// We received a string so pass it out!
						if ( ( receivedString.Length != 0 ) &&
							( ReceivedStringEvent != null ) )
						{
							ReceivedStringEvent( this , receivedString );
						}
					}
					// End of data reached.
					// Close socket so disconnected flag is set
					m_Socket.Close();
				}

				catch ( IOException e )
				{
					if ( ( e.InnerException is SocketException ) &&
						( ((SocketException)e.InnerException).NativeErrorCode
						== 10060 ) )
					{
						// This case is for Rx timeouts only.
					}
					else
					{
						// Throw the same exception again,
						// as if we never caught it locally
						throw;
					}
				}
				if ( m_SendList.Count != 0 )
				{
					m_StreamWriter.WriteLine(m_SendList[0].ToString() );
					m_StreamWriter.Flush();
					if ( SentStringEvent != null )
					{
						SentStringEvent( this , m_SendList[0].ToString() );
					}
					m_SendList.RemoveAt( 0 );
				}
			}
		}

		catch ( Exception e )
		{
			if ( !m_Socket.Connected )
			{
				if ( DisconnectedEvent != null )
				{
					DisconnectedEvent( this );
				}
			}
			else if ( ProtocolExceptionEvent != null )
			{
				if ( !m_Disposed )
				{
					ProtocolExceptionEvent( this , e );
				}
			}
		}
	}
The LineTextProtocol class functioned well and enabled network communications in the application it was written for, which is always the key test of any piece of code. When I first embarked on this project my instinct was to write code that pulled bytes through the socket directly using its asynchronous functions, cast them to characters, and assemble them into strings. Doing so would certainly have been less efficient, and have taken many more lines of code. It would also have been harder to debug and more likely to contain persistent bugs. By spending some time at the outset “surfing” the documentation and identifying a .NET way of doing things, I saved myself a lot of dull coding, intricate debugging and challenging maintenance. I also learned a valuable lesson, which is that persistence pays off.

It took some time to discover the Socket.SetSocketOption that was key to making this approach work, but like with so many things in .NET, it’s there if you look hard enough. The approach used to develop LineTextProtocol could be adopted to work with other interfaces, including RS232 (using the Platform Invoke facility in .NET), as well as a plethora of different network protocols.


Ian Stevenson has been developing Windows software professionally for almost 10 years, in areas ranging from WDM device drivers through to rapid-prototyping of enterprise systems. Ian currently works as a consultant for The Generics Group and can be contacted at [email protected].

You might also like...

Comments

About the author

Ian Stevenson United Kingdom

Ian Stevenson has been developing Windows software professionally for 10 years, in areas ranging from WDM device drivers through to rapid-prototyping of enterprise systems. Ian currently works a...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The first 90% of the code accounts for the first 90% of the development time. The remaining 10% of the code accounts for the other 90% of the development time.” - Tom Cargill