C# Create a Client and Server with TCPListener

C# Create a Client and Server with TCPListener

In this post were going to create a simple server using TCPListener and send a memory stream to it from a WPF Client. The memory stream will be broken up into chunks of bytes as follows;

Memory Stream Structure

This structure will allow us to have up to 256 option codes (OptCodes) that are 1 byte and will always be the first byte. The next block will be 4 bytes and will be used to store the byte size for the proceeding chunk of data. 4 bytes, or 32 bits, which allows us to store 65536*65536 distinct values. This gives a range of approximately 4 billion bytes of storage for the proceeding chunk. This pattern of 4 bytes and n bytes will be replicated allowing us to store n number of data sets within the memory stream.

Visual Studio Solution

The visual studio solution will be broken up into three projects; Client Side App (WPF Project), Server Side App (Console Project), and a Class Library Project for common code.

Visual Studio Solution

Visual Studio Need to Know

We will nee to know a couple of things in visual studio to be able to start two projects concurrently, within the solution property’s, under Startup Project settings we need to ensure that the Multiple Startup Projects option is enabled, and that the Console Project starts first and the WPF Project secondarily. The Action both must be set to Start and using the arrows organized as shown below.

Startup Project

In addition to this we want to be able to use the file selection object within the WPF application to do this we must double click on the WPF Project and add some additional XML tags as shown below. The “-windows” defines that the WPF project can only be compiled for windows, and the “UseWindowsForms” tag allows us to use System.Windows.Forms within the project for the file selection object.

WPF CSProj XML

WPF Application

The WPF application will show you how to connect to the server and how to send messages that contain text, images (files) so essentially anything you want, so lets get started, on the server side we can process this data anyway we want.

WPF XML

The XAML shown below creates a very basic WPF window that allows us to connect to the server with a given Option Code and then have the ability to send a Message and an Image selected from the Client that will be stored on the Server.

WPF Window
C#

Relay Command Base

The relay command will allow us to bind the WPF UI to our code behind using the MVVM pattern.

C#

Filesystem Helper

The Filesystem Helper in this case only has one method that allows a user to select a file that we will then convert to a byte array and append it to the memory stream being send to the server.

C#

Packet Writer Server

The Packet Writer Server, will create a new instance of the TCPClient, that we will use to connect tot he TCPListener on the server. This class will also contain any method of transmitting data, and we will need two to get started; Connect To Server and Send to Server. The Connect to Server method we have hard coded the servers IP Address and Port number, it would probably be better to get this data from a configuration file but for now this is fine. For the initial connection we send the Option Code and the windows User Name. The Send to Server method also sends an Option Code, but this time well also send a Message and an Image. We will get into the nitty gritty of the methods that build the Memory Stream in a second, it important to note that we also construct the Packet Reader Helper and Writer Helper within the methods and not in the class constructor, this stops old Messages being resent.

C#

View Model Base

When using the MVVM pattern we must implement INotifyPropertyChanged and the easiest way to do this is to construct this simple View Model Base and inherit it into all View Models.

C#

Main View Model

The Main View Model creates the logic behind the WPF UI, and creates the Packet Writer Server instance.

C#

Helpers Class Project

The two classes within this project are the heart and soul of this proof of concept application, and allow us to construct the deconstruct the memory stream in the way that we want to.

Packet Writer Helper

The Packet Writer Helper class will use the Binary Writer object to simplify the way in which we construct the memory stream. the Write Option Code method writes a single byte to the memory stream with a value of 0 to 255, so we can have up to 256 different message structures. Before each chunk of the memory stream we need to send how many bytes that will span the chunk. This is done with a 4 byte block or 32 bits of data or ‘Int32’, and is encapsulated by the Write Next Chunk Size method, which is called prior to writing a large chunk of data to the memory stream. The next two methods write string messages and files to the memory stream for the main data chunks and finally the method to convert the memory stream to a byte array.

C#

Packet Reader Helper

The Packet Reader Helper will take the Network Memory Stream from the TCPListener and allow us to decompose it back into the chunks of data being sent. The Read Options Code method reads a single byte to get the Option code which we can then interpret to understand which of the 256 options are being sent. The Read Chunk Size method is the key to detangling the memory stream into the chunks since it reads the four bytes prior to the data chunk and tells us how many bytes we must read for each data chunk. The Read Message and the Read File methods have been scaffolded out for the proof of concept and would need more wok to productionize them.

C#

Server Project

The Server Project is a Hosted Server application and can be compiled for either Windows or Linux, this proof of concept only writes data to the console for now.

Program (Console Class)

Were going to use dependency injection and hosted service to create an instance of our server, this keeps the console application nice and clean.

C#

Packet Reader Server

The Packet Reader Server implements IHostedService and has two Async Methods that need to be defined; Start Async and Stop Async. Within the Stop Async we simply return the Completed Task. The Start Async method creates the new TCPListener on the required IPAddress and Port to match the TCPClient. Then within the While loop each time a Client connects we create a new Client Connection which will handle the messaging from the client. This way each client connection manages the workload for its connected client on a separate thread, as we will see in a second.

C#

Client Connection Model

The Client Connection Model manages the initial Client Connection within its constructor, after which a separate process thread then takes care of any additional communication between the server and the client. The Process method is just a proof of concept and will be rewritten later on.

C#

Working Example

Application Started

When the application starts we can see that the Server Application starts first (Console Window), and then the WPF Application secondarily.

Application Started

Server Connection

When the user selects the Connect to Server button we can see in the Servers Console Window the connection being made and the User Name of the user making the connection.

Connecting to the Server

Send to Server

And if we give a Server message and a Path to the Server Image, when the user selects Send to Server , again we can see in the console that the Message and Image are sent to the server along with the chunk sizes for each chunk. This can now be expanded on to make an application with a server behind it.

Send Message to Server

Broadcasting a Message Back to the Client

So we can create a connection with the server and send data, now we want to be able to send data back to the client from the server.

WPF Connection Bubble

Within the Client Side WPF UI we will add an Ellipse that’s bound to a Connection Color Brush property.

Connection Bubble
C#

Server Messaging Helpers

Within the Server Project we will be creating a new Project Folder for Helpers.

Server Messaging Helpers

Within the new folder we will create a new class that’s dedicated to Broad Casting Messages back to the client, and we will start of with two methods as shown below.

C#

Client Connection Model

Within the Client Connection Model, we will add a call to the new BroadCastConnection method.

C#

Packet Writer Server

Within the PacketWriterServer on the client side, we need to create a listening process that listens to the PacketReaderHelper on a separate thread. This will invoke an Action when a specific OpCode is detected.

C#

Main View Model

Finally within the main view model we can subscribe to the Event, and in this case we will change the color of the Brush that’s Bound to the Ellipse indicating if there is an active connection.

C#

Connection Established Red Light Green Light

When the connection is made a return message from the server turns the ellipse color from Red to Green.

Red Light Green Light