This is part two of William's series on using Asynchronous Socket Utility Classes in C#. In this article, William will describe the code for the server side. Once you have read the two parts you should have no troubles with these classes.
Asynchronous Socket Utility Classes – Part II (Page 1 of 4 )
A socket is a connection oriented communication channel that is established between two computers. In the OSI network model, http://www2.rad.com/networks/1994/osi/layers.htm, sockets are implemented at the session layer. This means that sockets can be used with any transport protocol like TCP or UDP. Session layer protocols, like sockets, require that a computer must establish a connection to any computer it wished to communicate with. Once a connection is established, messages can be passed between both computers.
A socket connection can be thought of as a virtual pipe between two computers. Each pipe provides an exclusive communication channel. If multiple computers connect to the same computer, each will have their own pipe. It is easy to identify which computer sent a message because each message flows through that computers pipe. This means an application must be looking for messages on every pipe that exists. The most common way to do this is to spawn a thread for each pipe.
This thread just waits for messages to arrive on their respective pipe and then processes the message. This design works well until you have hundreds of pipes. Each pipe requires a thread and each thread has the potential to be in a running state at the same time. This solution is not scalable and will cause performance problems as the number of pipes and messages going through those pipes increase.
Asynchronous sockets provide a way to have a pool of threads process messages for all established pipes, instead of having a thread per pipe. This solution is scalable and improves performance. The .NET framework provides nice low-level classes to help us add asynchronous socket support into our applications. However, the implementation still lacks an organizational structure that is easy to use.
For more information on socket programming look at the follow sites:
When adding asynchronous socket support into our applications it can seem initially confusing, and at times overwhelming. We have to understand how the asynchronous socket framework is implemented. We need to understand threading and how it is applied. Most importantly we need to have some understanding of how to integrate this into our application.
To help us through these issues, I have built two classes. These classes provide reusable interfaces, which cleanly and quickly add asynchronous socket support into our applications. Both of these classes take care of the low-level details that allow us to only have to worry about coding the business problem at hand. Low level details such as implementing the asynchronous socket thread pool, identifying which messages came from which computers, and handling any error conditions that occur in a consistent way.
These classes will save us hours of time developing and debugging our asynchronous socket applications. In this article I will build the server socket class and sample application to test it.
A basic understanding of C# is required to follow through the examples and the classes. Basic concepts of type, properties, threading, synchronization, and delegates are required. It is important that you have completed part I of this article. In that article we build the CSocketServer class.
Defining The Problem
High-level class needs to be developed that abstract the .NET framework classes used to develop asynchronous socket applications. This new class needs to abstract the details behind asynchronous socket programming. This class must be easy to use and reliable. Any classes that are developed need to be reusable so they can be shared among many different types of applications.
Defining The Solution
A single class will be developed. We will develop a class that abstracts the intricacies of building asynchronous socket servers. This class will allow us to be ignorant of the details and yet allow us to access the underlining framework if we need to.