You are on page 1of 9

Multithreaded TCP Network Server This project, Multithreaded TCP Network Server is a server which is used to used for

multithread client connection handling and collective management for client connection . This application software Uses TCP Protocol to interact with the clients. The main task of this application is to check the status of client and interact with them. This application software is used for intranet systems to monitor various hosts or clients connected to the server. The main task is to check the connected host to the server and sent message across the network in the intranet system. This application software is used for getting the System/hardware configuration of the connected hosts or client to the TCP network server. It also shows the running application on the desired client. It is used to establish communication between the connected clients to the intranet system. It is basically used in System Auditing for organization having a large intranet system. This application software is implemented with help of C#.NET and asp.NET. The .NET socket network Programming helps us to incorporate these features very easily and efficiently. FEATURES :1.This project is taken up for studying and handling the various TCP/IP communications with the help of provisions made in .Net frame work under different scenario. 2.Primary focus is to establish TCP/IP network environment as well as UDP environment under given LAN environment and subsequently establish a socket based fool-proof communication together with possible persistent error handling mechanism, in created network by application. 3.In next phase of application development, creation of utilities, handling multi channel communication in network would be developed. This utility shall have, trace history recording facility in built in it. Administrator and nodes can send and receive messages / notices / warning on this network. 4.Further, established network created by current application would be made, to use availability of hardware connected in network. It would be used for auto detection of removal of parts from connected node in network or identification of changes made in the state of nodes which can be used as centralized controlling utility for multi departmental computer laboratory in any organization.

Introduction With the new release of the .NET framework, creating a sophisticated TCP Server is just like eating a snack! Basic features including multi-thread client connection handling, collective management for client connections with thread safe collection object, and background reclaiming of all doomed connections, are all easy to address. Tools This example was built on the Microsoft .NET Framework SDK version 1.0.3705 (with SP2), I suggest you use the latest version wherever you can acquire one. A simple editor should be enough to begin your coding and I have used C# to create all programs and compiled it with the C# compiler that comes with the SDK. There are several source files and commands to produce executables are as follows: CSC CSC CSC CSC CSC TcpServer.cs TcpServer2.cs TcpServer2b.cs TcpServer3.cs TcpClientTest.cs

TCP Classes

Coming with the framework are the very useful classes TcpListener and TcpClient in the namespace System.Net.Sockets, which provided most of the needed TCP network task for building TCP applications. In just several simple statements will give a simple TCP listening service for the TCP server: TcpListener listener = <span class='cs-keyword'>new</span> TcpListener(portNum); listener.Start(); TcpClient handler = listener.AcceptTcpClient(); <span class='cs-keyword'>int</span> i = ClientSockets.Add ( <span class='cs-keyword'>new</span> ClientHandler(handler) ) ; ((ClientHandler) ClientSockets[i]).Start() ; In the third line of the above statements allows the TCP server to accept incoming client connections, each connections will give a separated TcpClient instance representing individual client connections. Since each client connections is handled in separated threads, the class ClientHandler will encapsulate client connection and a new thread will be created and started (that is what the last two lines in the above statements do). Thread Safe Collection As to managing client connections, especially when reclaiming doomed client connections and shutting them down before ending the main TCP server thread, an ArrayList object is so handy and comes into the game as a thread safe collection bag for all client connections. The followings lines depict how thread safe access to ArrayList can be achieved: <span class='cs-keyword'>private</span> keyword'>static</span> ArrayList ClientSockets <span class='cs-

<span class='cs-keyword'>lock</span> ( ClientSockets.SyncRoot ) { <span class='cs-keyword'>int</span> i = ClientSockets.Add ( <span class='cs-keyword'>new</span> ClientHandler(handler) ) ; ((ClientHandler) ClientSockets[i]).Start() ; } The keyword lock provided thread-synchronized access to a property SyncRoot of the instance of ArrayList, ClientSockets, a collection of object instances of class ClientHandler, representing TCP client connections.

Background TCP Client Reclaiming Thread In a typical TCP servicing environment, many clients making connections will mix with clients which are dropping their connections at the same time, and such dropped connections should be properly release their held resources. Without reclaiming means server will soon be overloading with doomed client connections, which hold sacred resources without releasing them back to system. The following code shows the reclaiming of the thread in my application: ThreadReclaim = <span class='cs-keyword'>new</span> Thread( <span class='cs-keyword'>new</span> ThreadStart(Reclaim) ); ThreadReclaim.Start() ; <span class='cs-keyword'>private</span> <span class='cskeyword'>static</span> <span class='cs-keyword'>void</span> Reclaim() { <span class='cs-keyword'>while</span> (ContinueReclaim) { <span class='cs-keyword'>lock</span>( ClientSockets.SyncRoot ) { <span class='cs-keyword'>for</span> ( <span class='cskeyword'>int</span> x = ClientSockets.Count-<span class='csliteral'>1</span> ; x >= <span class='cs-literal'>0</span> ; x-- ) { Object Client = ClientSockets[x] ; <span class='cs-keyword'>if</span> ( !( ( ClientHandler ) Client ).Alive ) { ClientSockets.Remove( Client ) ; Console.WriteLine(<span class='cpp-string'>"A client left"</span>) ; } } } Thread.Sleep(<span class='cs-literal'>200</span>) ; } } As the reclaiming thread will compete with main thread to access the client connections collection, synchronized access is needed when checking dead connections before removing them.

Maybe some readers ask me why I did not choose to use features like callbacks or delegates to let client connection instances unregister themselves from the collection, this I will explain later.

Clean Shutdown Before stopping the main server, closing all connections properly is also very important: ContinueReclaim = <span class='cs-keyword'>false</span> ; ThreadReclaim.Join() ; <span class='cs-keyword'>foreach</span> ( Object Client <span class='cs-keyword'>in</span> ClientSockets ) { ( (ClientHandler) Client ).Stop() ; } First, the resource reclaiming thread is ended and a global variable ContinueReclaim is responsible for controlling it. In addition, it is waited to be properly stopped before the main thread starts going on to the next step. Finally, a loop is started to drop each client connections listed in ClientSockets, as this time only the main thread is accessing it no threadsynchronisation code is needed. Here I would like to explain why I do not use a callback or delegate to address the reclaiming task. Since the main thread needs to hold the ClientSockets collection exclusively while dropping the client connections, it would have produced deadlock as the client connection trying to access ClientSockets collection tried to use callback or delegate to unregister itself and at the same time main thread was waiting client connection to stop! Of course some may say using timeout while client connection class trying to access ClientSockets collection is an option, I agree it could solve the problem but as I always prefer a cleaner shutdown, using a thread to control resource reclaiming task would be a better idea. Thread Pooling Things seem so fine when there are not too many clients connecting at the same time. But the number of connections can increase to a level that too

many threads are created which would severely impact system performance! Thread pooling in such a case can give us a helping hand to maintain a reasonable number of threads created at the same time base on our system resource. A .NET class ThreadPool helps to regulate when to schedule threads to serve tasks on the work-item queue and limit the maximum number of threads created. All these functions come as a cost as you lose some of the control of the threads, for example, you cannot suspend or stop a thread preemptively as no thread handle will be available by calling the static method: public static bool QueueUserWorkItem(WaitCallback); of class ThreadPool. I have created another example to let all client connections be scheduled to run in thread pool. In the sample program TcpServer2.cs is several amendments I have made. First, I do not use a collection object to include client connections. Secondly, there is no background thread to reclaim the doomed client connections. Finally, a special class is used to synchronize client connections when the main thread comes to a point to instruct ending all of them. Reschedule Task Item in Thread Pool As the client handling task scheduled in the thread pool created on the previous example will tend to hold the precious thread in the thread pool forever, it will restrict the scalability of the system and large number of task items cannot get a chance to run because the thread pool has a maximum limit on the number of threads to be created. Suppose even though it did not impose a limit on number of threads created, too many threads running still lead to CPU context switching problems and bring down the system easily! To increase the scalability, instead of holding the thread looping with it, we can schedule the task again whenever one processing step has finished! That is what I am doing in example TcpServer2b.cs; trying to achieve the client task handling thread function returns after each logical processing step and try rescheduling itself again to the thread pool as the following code block shows: <span class='cs-comment'>// Schedule task again </span> <span class='cs-keyword'>if</span> ( SharedStateObj.ContinueProcess && !bQuit ) ThreadPool.QueueUserWorkItem(<span class='cs-keyword'>new</span> WaitCallback(<span class='cs-keyword'>this</span>.Process), SharedStateObj); <span class='cs-keyword'>else</span> { networkStream.Close(); ClientSocket.Close();

<span class='cs-comment'>// Deduct no. of clients by one</span> Interlocked.Decrement(<span class='cs-keyword'>ref</span> SharedStateObj.NumberOfClients ); Console.WriteLine(<span class='cpp-string'>"A client left, number of connections is {0}"</span>, SharedStateObj.NumberOfClients) ; } <span class='cs-comment'>// Signal main process if this is the last client connections </span> <span class='cs-comment'>// main thread requested to stop.</span> <span class='cs-keyword'>if</span> ( !SharedStateObj.ContinueProcess && SharedStateObj.NumberOfClients == <span class='cs-literal'>0</span> ) SharedStateObj.Ev.Set(); No loop is involved and as the task tries to reschedule itself and relinquish thread it held, other tasks get a chance to begin running in the thread pool now! Actually this is similar capability to what the asynchronous version of the socket functions provide, task get, waiting and processing in the thread pool thread needs to reschedule again at the end of each callback functions if it want to continue processing. Use Queue with Multiple Threads Using a queue with multiple threads to handle large numbers of client requests is similar to the asynchronous version of the socket functions which use a thread pool with a work item queue to handle each tasks. In example TcpServer3.cs, I have created a queue class ClientConnectionPool and wrapped a Queue object inside: <span class='cs-keyword'>class</span> ClientConnectionPool { <span class='cs-comment'>// Creates a synchronized wrapper around the Queue.</span> <span class='cs-keyword'>private</span> Queue SyncdQ = Queue.Synchronized( <span class='cs-keyword'>new</span> Queue() ); } This is mainly to provide a thread safe queue class for later use in the multithreaded task handler, ClientService, part of its source shown below: <span class='cs-keyword'>class</span> ClientService { <span class='cs-keyword'>const</span> <span keyword'>int</span> NUM_OF_THREAD = <span literal'>10</span>; class='csclass='cs-

<span class='cs-keyword'>private</span> ClientConnectionPool ConnectionPool ; <span class='cs-keyword'>private</span> <span class='cskeyword'>bool</span> ContinueProcess = <span class='cskeyword'>false</span> ; <span class='cs-keyword'>private</span> Thread [] ThreadTask = <span class='cs-keyword'>new</span> Thread[NUM_OF_THREAD] ; <span class='cs-keyword'>public</span> ClientService(ClientConnectionPool ConnectionPool) { <span class='cs-keyword'>this</span> .ConnectionPool = ConnectionPool ; } <span class='cs-keyword'>public</span> <span class='cskeyword'>void</span> Start() { ContinueProcess = <span class='cs-keyword'>true</span> ; <span class='cs-comment'>// Start threads to handle Client Task</span> <span class='cs-keyword'>for</span> ( <span class='cskeyword'>int</span> i = <span class='cs-literal'>0</span> ; i < ThreadTask.Length ; i++) { ThreadTask[i] = <span class='cs-keyword'>new</span> Thread( <span class='cs-keyword'>new</span> ThreadStart(<span class='cs-keyword'>this</span>.Process) ); ThreadTask[i].Start() ; } } <span class='cs-keyword'>private</span> <span class='cskeyword'>void</span> Process() { <span class='cs-keyword'>while</span> ( ContinueProcess ) { ClientHandler client = <span class='cs-keyword'>null</span> ; <span class='cs-keyword'>lock</span>( ConnectionPool.SyncRoot ) { <span class='cs-keyword'>if</span> ( ConnectionPool.Count > <span class='cs-literal'>0</span> ) client = ConnectionPool.Dequeue() ; } <span class='cs-keyword'>if</span> ( client != <span class='cskeyword'>null</span> ) { client.Process() ; <span class='cs-comment'>// Provoke client</span> <span class='cs-comment'>// if client still connect, schedufor later processingle it </span>

<span class='cs-keyword'>if</span> ( client.Alive ) ConnectionPool.Enqueue(client) ; } Thread.Sleep(<span class='cs-literal'>100</span>) ; } } } Using the Dequeue and Enqueue functions, it is so easy to give tasks handling based on the FIFO protocol. Making it this way we have the benefit of good scalability and control for the client connections. I will not provide another Asynchronous Server Socket Example because the .NET SDK already has a very nice one and for anyone interested please goto the link Asynchronous Server Socket Example. Certainly Asynchronous Server Sockets are excellent for most of your requirements, easy to implement, high performance, and I suggest reader have a look on this example. Conclusion The NET framework provide nice features to simplify multi-threaded TCP process creation that was once a very difficult task to many programmers. I have introduced three methods to create a multi-threaded TCP server process. The first one has greater control on each threads but it may impact system performance after a large number of threads are created. Second one has better performance but you have less control over each thread created. The last example gives you the benefit of bothscalability and control, and is the recommended solution. Of course, you can use the Asynchronous Socket functions to give you similar capabilities, whilst my example TcpServer2b.cs, which gives you a synchronous version with thread pooling, is an alternative solution to the same task. Many valuable alternatives and much depends on you requirements. The options are there so choosing the one best suited your application is the most important thing to consider! Full features can be explored even wider and I suggest that readers look at the .NET documentation to find out more.

You might also like