Click here to Skip to main content
13,356,318 members (59,015 online)
Click here to Skip to main content
Add your own
alternative version


195 bookmarked
Posted 22 Jul 2004

Single Server With Multiple Clients : a Simple C++ Implementation

, 22 Jul 2004
Rate this:
Please Sign up or sign in to vote.
Implement a client/server structure with multiple clients using simple C++ classes

0. Introduction

This article presents the details of TCP/IP socket programming in C++. After reading this article, you will be able to build your own server that is able to handle multiple clients at the same time. Several key classes are developed in this article, and hopefully, you will have the chance to use these classes in your daily development work. The first one is myTcpSocket, this class hides the details of socket programming by providing a simple and easy-to-use interface, it is used to build both the server and client. The second class is myThread class whose main purpose is to make server to handle multiple clients simultaneously: for each incoming client call, the server will create a separate thread to communicate with this client, therefore it can handle as many incoming clients as there are. In a multi-thread environment like this, however, synchronization of these threads is always an important issue. To solve this problem, we need our last major class, namely, mySemaphore.

The following are the reasons why you might be interested in this article:

  1. You might want to know the details of client/server programming. Sure, .NET is all about XML and web services, and it provides a whole new framework to make your life easier, but the foundation of its network part is still socket programming, and understanding the details about socket programming will make us not only feel easier, but also happier.
  2. You might want to develop application that has the client/server structure but for some reason, you cannot use the APIs/classes from MFC or C#. For instance, if the application is to be developed on a Unix/Linux platform, then these APIs/classes are not even available. If you have a situation like this, hopefully you can remember the classes that we present here and give them a try: they are light-weighted and quite generic, they can be easily used with no need to provide any window handle or whatsoever, also they can be incorporated easily into applications that are developed on Unix/Linux platform by making simple changes to these classes.
  3. Your application is not necessarily client/server oriented, but still you need a set of generic and low-level building blocks for sockets. One example is that your application might need inter-process communication (IPC) methods, then myTcpSocket can be at least one of your candidates. Other applications may involve multi-threading, in this case, myThread and mySemaphore classes could be helpful to your work.

One last reason, my earlier article, "A light-weighted client/server socket class in C++" (we will call this article #1 in later discussion), is about a single server and single client, and one reader asked me if we can make the server to handle multiple clients. Well, here is the answer for you, hope you have a chance to see this article too.

Hope this gives you the motivation to read this article. The next section will describe the client/server scenario that is implemented in this article, then we discuss how to build/compile the project if you want to try it out yourself. The next several sections present the details of implementing the client/server structure using the above-mentioned key classes - this also serves as an example of how to use these generic classes in real applications.

1. Client/Server Scenario

The client/server structure we are interested in is described as follows. The server will be started first and after it is started, we want the server to wait for the incoming client calls, and periodically report its status: how many clients have been connected with the server and how many clients have been disconnected with the server. Meanwhile, once an incoming call is detected and accepted, the server will create a separate thread to handle this client, it will therefore create as many separate sessions as there are incoming clients and it should be able to "talk" with any one of these clients. Once the server receives a Quit/quit message from one of these clients, it will shutdown the connection with this particular client.

Again, to implement this client/server scenario, we will first build several key classes, namely, myTcpSocket, myThread and mySemaphore. In the next section, we will discuss how to compile/build the project and we will then describe these classes and implementation details in the next several sections.

2. How To Build and Run the Project

You can download the source code and the following .cpp and .h files should be included in the zip file:

For the server:


For the client:


After downloading these files, you can then build two projects: one for the server and one for the client. After compiling, you should start the server first. Successfully starting the server will show the following console screen:

my localhost (server) information:
        Name:    liyang

Summary of socket settings:
   Socket Id:     1936
   port #:        1200
   debug:         false
   reuse addr:    false
   keep alive:    false
   send buf size: 8192
   recv bug size: 8192
   blocking:      true
   linger on:     false
   linger seconds: 0

server finishes binding process...
server is waiting for client calls ...

This assumes that you are using your local PC as the server, therefore, Name should show your domain name (or, in some case, your PC's name, like in this example), and Address should show your current IP address (depending on your ISP, your IP address can change from time to time. At the time I was running the server, this IP address was

Clearly, in order to communicate with your server, you need to let your client know the IP address of your server. To do so, you need to create a simple text file named serverConfig.txt which contains only one line: the IP address of the server. So add into this file and save it in the directory where you client executable resides, and then start the client by double-click this executable. You can start as many clients as you want and you can send messages from server to any of these clients by typing on the keyboard, also, you can send messages from any client to the server again by typing a string on the keyboard. To end a client, send the message Quit or quit from the client to server, this client will be terminated. Have fun playing with this simple client/server system!

In the next few sections, we will discuss the classes in details and show how to use these classes to implement this client/server system.

3. myTcpSocket class

In this section, myTcpSocket class is described. In fact, article #1 presents a rather detailed description about this class, so here let us only show the key methods of this class by using the following examples. In a nutshell, this class encapsulates socket-related system calls into a single class to offer a simple and easy-to-use interface, a typical usage of this class (as a server) is shown as follows:

// server side
myTcpSocket myServer(PORTNUM);  // create the socket using the given port numberx
myServer.bindSocket();          // bind the socket to the port number
myServer.listenToClient();      // listening to the port/socket

while ( 1 )
   // waiting for the client call...
   string clientName;
   myTcpSocket* newClient = myServer.acceptClient(clientName);   

   // if we reach here, the server got a call already...
   // declare string messageToClient,messageFromClient;

   // receive message from client

   // send message to client

   // other stuff here ...

The following code shows the usage of myTcpSocket class on the client side:

// client side
myTcpSocket myClient(PORTNUM);  // create the client socket using the given port id
         // connect to server at IP addr

while (1)
   // declare string messageToServer, messageFromServer...
   // send message to server

   // get message from server  
   int messageLength = myClient.recieveMessage(messageFromServer);
   // other stuff...

Besides these major methods in myTcpSocket class, there are other methods you can use to manipulate the socket, for example:

void setDebug(int);
void setReuseAddr(int);
void setKeepAlive(int);
void setLingerOnOff(bool);
void setLingerSeconds(int);
void setSocketBlocking(int);

With all these being said, it is now easy to see how to construct a very basic client/server system using the above server side and client side code (see article #1). However, the following problems still exist in this basic model:

  1. The server will not be able to handle multiple clients;
  2. If we place the above server side code in main() function, the myServer.acceptClient() call inside the while loop will block everything, we cannot implement any other processing task in main(), for example, what if we also want to collect the performance status of the server, such as how many clients have made the connection, etc., the blocking structure prevent us from doing anything else!

To solve these problems, we need two more classes, namely, myThread and mySemaphore. These classes are discussed in the next section.

4. Two more key classes: myThread, mySemaphore

The existing problems discussed in the previous section suggest that multithreading be the best solution: 1. to handle multiple clients, we can create a thread for each incoming client call, and this thread will handle the communication between the server and this particular client; 2. the problem of making blocking calls and continuing processing can be solved by creating a thread: you can call the blocking function in this thread and let the main thread continue its processing without waiting.

myThread can be used for this situation, it is also a generic class that can be easily used in the development of other applications. Its main functionalities include the following: create a thread, start to execute a thread, suspend/resume a thread, wait for a thread to finish and get access of its exit code, access the settings of a thread (for instance, the priority of a thread), and report time statistics of a thread, etc. For details of this class and its usage example, you can read my previous article, "Producer/Consumer Implementation Using Thread,Semaphore and Event" (we call this article #2 in later discussion).

Let us now take a look at how to use myThread class together with myTcpSocket class to create a client/server system and solve the previous two problems. Here is the improved (but also simplified) main() function on the server side (don't worry the details):

int main()
   // initialization, and declaration of variables, etc.

   // Initialize the winsock library

   // create the server: open socket on the local host(server)
   myTcpSocket myServer(PORTNUM);

   // create a thread to implement server process: 
   // listening to socket,accepting client calls,
   // communicating with clients, etc. This will free the 
   // main control (see below) to do other stuff.
   myThreadArgument* serverArgument = new myThreadArgument(
   myThread* serverThread = new myThread(serverHandleThread,(void*)serverArgument);

   // main control: since the above serverThread is handling the server functions,
   // this main control is free to do other things.
   while ( 1 )
      // do whatever you need to do here, I am using 
      // Sleep() to make a little delay, 
      // pretending to be the other possible processings you might want to do...

      // report the server status here...
      // code used to report server status
   return 1;

Examining the above main() function, one can tell that instead of calling the blocking function which will listen/accept the incoming clients, the main thread will only do the initialization work and create the server instance, the blocking call (acceptClient()) is moved to a thread created by the main thread, this thread is serverHandleThread. Therefore, the main function is free to do any other processing you might want to do, for instance, reporting the status of the server (you can see the details in the source files you downloaded). This discussion can be more clear if you continue to examine the definition of the server thread, serverHandleThread, that is created in the main() function (again, a simplified version):

DWORD WINAPI serverHandleThread(LPVOID threadInfo)
   // other stuff...

   // get the server
   myTcpSocket* myServer = serverArgument->getClientConnect();
   string serverName = serverArgument->getHostName();

   myServer->bindSocket();      // bind the server to the socket
   myServer->listenToClient();  // server starts to wait for client calls

   // initialize the threads that will be generated to handle
   // each incoming client
   myThreadArgument* clientArgument[MAX_NUM_CLIENTS];
   myThread* clientHandle[MAX_NUM_CLIENTS];
   for ( int i = 0; i < MAX_NUM_CLIENTS; i++ )
      clientArgument[i] = NULL;
      clientHandle[i] = NULL;

   int currNumOfClients = 0;
   while ( 1 )
      // wait to accept a client connection,processing 
      // is suspended until the client connects
      myTcpSocket* client;    // connection dedicated for client communication
      string clientName;      // client name 
      client = myServer->acceptClient(clientName);    
      // other stuff...

      // for this client, generate a thread to handle it so we can 
      // continue to accept and handle as more clients as we want
      if ( currNumOfClients < MAX_NUM_CLIENTS-1 )
         clientArgument[currNumOfClients] = new myThreadArgument(
         clientHandle[currNumOfClients] = new myThread(clientHandleThread,
   return 1;

To see how we can handle multiple clients, notice that once acceptClient() returns, i.e., an incoming client call is received and accepted, the above server thread will not start the communication with this client, instead, it will create a new thread, called clientHandleThread, pass the client connection to this thread, and let the communication between the server and this new client become the full-time job for this newly created thread. It will then go back to wait for another incoming call, and create yet another new thread to handle the new incoming client. By doing so, the server can handle as many clients as there are. The main flow in the clientHandleThread is shown as follows (simplified version):

DWORD WINAPI clientHandleThread(LPVOID threadInfo)
   // some related stuff ...

   // get the client connection: receiving messages from 
   // client & sending messages to the 
   // client will all be done by using this client connection
   myTcpSocket* clientConnection = clientArgument->getClientConnect();
   string clientName = clientArgument->getHostName();

   // the server is communicating with this client here
      string messageFromClient = "";
      // receive from the client
      int numBytes = clientConnection->recieveMessage(messageFromClient);
      // send to the client
      // ... construct a message to send, saved in messageToClient
      // other possible stuff ...


   return 1;

Now that we have presented the solutions to the two problems that the simple client/server structure has, we need to take a look at the client side. Fortunately, with the understanding of the above solution, it is much easier to understand the client side code, you should be able to read the code you downloaded with no problem.

The other class needed to discuss in this section is mySemaphore class. Aagain, once multiple threads are involved, we right away have the synchronization issue. mySemaphore class is developed for this purpose. For example, if some/all the client threads need to access some global variable(s), this class will be extremely helpful. In our case, since we are only developing a framework for the client/server structure, i.e., we don't really have a specific application to fit, we don't really have a serious synchronization issue here. However, just to show the usage of this class, we treat the console screen and the log file as the global resources, and we use this class to synchronize the access to this global resource.

The basic function set provided by this class is quite intuitive: you can create a semaphore instance by actually creating a new semaphore or openning an existing one. After having the semaphore instance, you can lock it (either wait on it until you can successfully lock it or simply try and return if you cannot lock it at the moment), unlock it, change its settings (initial count, maximum count, etc) etc.

It is clear that this class encapsulates the WIN32 semaphore APIs, and, indeed, one can find a CSemaphore class in MFC that provides wrappers to some of these APIs as well, however, believe it or not, CSemaphore lacks a method to wait for the semaphore to be released, which, perhaps, is considered to be one of the key functions of this class! Since the application of this class is quite straightforward and intuitive, we are not going to discuss this class in more details, you can read article #2 to understand more about this class. It is also worth of mentioning this class is generic enough to be used in other application developments.

5. Several Helper Classes: myHostInfo, myEvent, myThreadArgument, myLog and myException

Up to this point, you should not have any big problems reading and understanding the code. When you are going through the code, you may also notice several other classes that we developed. In this section, we will briefly discuss these helper classes, again, all these classes are presented in much better detail in article #2, you can read it if you need to know more.

In a client/server environment, even before you can construct the client/server structure, you need to figure out several trivial yet important questions: if I am using my local PC as the server or client, what is the domain name and what is the IP address of my local PC? For the remote server, if I know its domain name is, how do I know its IP address, or, if I know the IP address of the server, how do I know its domain name? All these questions will be answered by using myHostInfo class: if you pass a domain name to the constructor, this class will tell you the IP address and if you pass in an IP address to the constructor, it will tell you the domain name. If you are using your local PC, you can use the constructor which takes no parameter and you can query both the name and the IP address from this class. Again, read article #1 to get more information.

myEvent class is another generic class that is used in the client/server structure. Its main purpose is to keep the main thread informed about which client thread has terminated its communication session so the main thread can report the server status. In article #2, its main usage is to terminate a thread safely. Therefore, in both applications, this class is of the function of a signal class. Article #2 presents a much more detailed description of this class. Also, article #2 presents myThreadArgument class in detail, its main purpose is to pack a set of parameters and feed this set to the thread so the thread and its parent thread can share key information.

myLog class, as its name suggested, is mainly for the purpose of understanding what is going on in the system since debugging a system with multithread could be difficult. If you don’t need the log, you can search for winLog in all the .cpp files and comment them out. Also, in order to capture the possible errors, a simple myException class is provided. We recommend that you keep this class, it is quite simple and easy to understand anyway.

6. An Example

Now that we finished all the necessary classes, we can present one example. In order to save the space on the CP server, I did not use any screen shots, but instead just pasted part of the log file into this article. Notice this log file was from the server side, you can see all the sessions between the server and each client, also you can see the periodical status report the server produced. Again all the messages were typed from the keyboard, also, I used my own PC as both the server and client - it will be more fun if you could find two PCs and make them talking to each other.

DATE: 07/23/04 - 01:04:22                    syslog.log

system started ...
initialize the winsock library ... successful

Retrieve the local host name and address:
        ==> Name: liyang
        ==> Address:

Summary of socket settings:
   Socket Id:     1936
   port #:        1200
   debug:         false
   reuse addr:    false
   keep alive:    false
   send buf size: 8192
   recv bug size: 8192
   blocking:      true
   linger on:     false
   linger seconds: 0

server finishes binding process... 
server is waiting for client calls ... 

server (name:liyang) status report:
   the following clients have successfully connected with server: 
   the following clients have shutdown the connection: 

==> A client from [liyang-A] is connected!
==> A client from [liyang-B] is connected!
==> A client from [liyang-C] is connected!

[RECV fr liyang-A]: hi, this is client A.
[SEND to liyang-A]: hello, A
[RECV fr liyang-B]: this is client B
[SEND to liyang-B]: hello, B
[RECV fr liyang-C]: this is C1
[SEND to liyang-C]: no, you are C!

server (name:liyang) status report:
   the following clients have successfully connected with server: 
   the following clients have shutdown the connection: 

[RECV fr liyang-C]: yes, it was a typo!
[SEND to liyang-C]: okay!
[RECV fr liyang-A]: so, who has connected with you?
[SEND to liyang-A]: you, B and C.
[RECV fr liyang-B]: any news?
[SEND to liyang-B]: no, everything is cool.

server (name:liyang) status report:
   the following clients have successfully connected with server: 
   the following clients have shutdown the connection: 

[RECV fr liyang-C]: in that case, I am leaving.
[SEND to liyang-C]: bye!
[RECV fr liyang-C]: quit
[RECV fr liyang-A]: what about now?
[SEND to liyang-A]: you and B.

server (name:liyang) status report:
   the following clients have successfully connected with server: 
   the following clients have shutdown the connection: 

[RECV fr liyang-B]: I am also leaving.
[SEND to liyang-B]: okay, come back!

==> A client from [liyang-D] is connected!

[RECV fr liyang-D]: hello, are you there?
[SEND to liyang-D]: yes!

server (name:liyang) status report:
   the following clients have successfully connected with server: 
   the following clients have shutdown the connection: 

[RECV fr liyang-A]: anything new?
[SEND to liyang-A]: client D is also connected!
[RECV fr liyang-A]: good! ask D if anything is new.
[SEND to liyang-A]: okay.
[RECV fr liyang-D]: nothing is new!
[SEND to liyang-D]: okay.

server (name:liyang) status report:
   the following clients have successfully connected with server: 
   the following clients have shutdown the connection: 

7. Conclusion

This article presents the implementation of a client/server structure where the server can handle multiple clients at the same time. Several key classes are developed in this application and they are also generic enough to be used in other applications. Hope this will be of some help to your development work and certainly welcome any suggestions and comments.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

liyang yu
Web Developer
United States United States
I love to tell jokes and today, I finally came up with my own joke. here it goes:

I decide to make my first son a medical doctor so later on when I am old and sick, I can get medical care any time I need and for free..., in fact, better to make my second son a medical doctor too so I can get a second opinion.

here is another version of this joke:

I decide to make my first son a medical doctor so later on when I am old and sick, I can get medical care any time I need and for free..., in fact, better to make my second son a medical doctor too so I can get a second opinion. well, perhaps my third son should be a lawyer - in case something is wrong with my medical care, I can sue the first two for free.

if you happen to visit this page and read these two jokes, tell me which one you like...

You may also be interested in...


Comments and Discussions

GeneralRe: VS2008 Project Source Code Pin
Sergey Chepurin25-Jul-12 22:09
memberSergey Chepurin25-Jul-12 22:09 
GeneralRe: VS2008 Project Source Code Pin
Member 80394272-May-12 8:50
memberMember 80394272-May-12 8:50 
GeneralRe: VS2008 Project Source Code Pin
p[R]ogramme[R]17-May-15 6:18
professionalp[R]ogramme[R]17-May-15 6:18 
GeneralRe: VS2008 Project Source Code Pin
Member 1309006829-Mar-17 6:44
memberMember 1309006829-Mar-17 6:44 
GeneralMy vote of 5 Pin
ssouwwikk13-Jul-11 23:12
memberssouwwikk13-Jul-11 23:12 
Generalsocket programin Pin
abrar yousaf19-Dec-10 2:29
memberabrar yousaf19-Dec-10 2:29 
Generalsocket programing Pin
abrar yousaf19-Dec-10 2:27
memberabrar yousaf19-Dec-10 2:27 
GeneralSocket Programing Pin
abrar yousaf19-Dec-10 2:24
memberabrar yousaf19-Dec-10 2:24 
Make a Client/Server application with the following specifications.
 The server will be able to handle multiple clients at a time. Multiple processes are required for this application.
 In this assignment a single file is received half from one client and half from the other two clients. This means that a single file will be gathered from 3 clients. You can understand that from the following scenario
0 - 50% 51-75% 76-100%
Client 1 portion
Client 2 portion
Client 3 portion
 The server must bind on port number 9999.
 Client application will take one argument at startup and that is the IP of the server
 When the connection is established, server will send file name to the client which it wants to receive
 The server will first send the length of the name of the file to the clients in two bytes.
 It will then send the file name to the client.
 If the file is not found at the client, the server and client both will close the connection
 The server will then assign the portion number of the file to the client in a single message i.e I, II, or III. (You are free to define a message for this message)
 In case the file is present at the client, the client will start making frames in the format shown below and will start sending it to the server. Keep in mind the client must start making frame from appropriate byte of its starting portion. The starting portion for the one client must not overlap the ending byte of the other client.
| Packet length | Payload length | Payload |
Packet length (2 byte)  Length of the entire packet
Payload length (2 byte)  Length of payload
Payload (variable)  Data from file
 The client will continuously send the data to the server till it reaches the end of its portion (may be the end of file).
 The server will then start parsing the received data.
 After parsing each frame and extracting the file data from it, the server will write (append) the data in a file.
 After sending all the data, the client will terminate its connection from the server.
 Make sure you assemble the file correctly, as this assignment will also check archive transfer; and that should be extracted at the client side.
 This assignment will also be checked with multiple clients receiving file at the same time
You should consider this thing that in order to assemble a file correctly, the portion must be written in the file after all the previous portions are completely written in that file i.e III portion can only be written if portion I and portion II has been written already in the assembled file.
Make sure that your application will follow the same API as required. Your application should also be able to run with ANY other application having the SAME specifications. Make your application to support the asked specifications ONLY. Also provide a README file if you made any assumptions. Please make sure to enable your application to support the APPROPRIATE BYTE ORDERING whenever necessary.
(Make file: 2 + appropriate data structures: 3 + Successful Compilation: 5 + Functionality: 15 )
Generalplease help me with my project.. plz.. Pin
ieqa440929-Sep-10 21:15
memberieqa440929-Sep-10 21:15 
QuestionVS08 Compile Error Pin
LordHogFred30-Nov-09 2:45
memberLordHogFred30-Nov-09 2:45 
AnswerRe: VS08 Compile Error Pin
Voids16-Aug-10 20:36
memberVoids16-Aug-10 20:36 
AnswerRe: VS08 Compile Error Pin
ledzaco7-Sep-10 5:06
memberledzaco7-Sep-10 5:06 
AnswerRe: VS08 Compile Error Pin
elgaabeb22-Sep-11 3:50
memberelgaabeb22-Sep-11 3:50 
Generalcode Pin
kufeji3-Aug-09 10:11
memberkufeji3-Aug-09 10:11 
GeneralRe: code Pin
arturorrg24-Sep-09 8:20
memberarturorrg24-Sep-09 8:20 
GeneralRe: code Pin
Yaniv Kaplan22-Oct-09 12:48
memberYaniv Kaplan22-Oct-09 12:48 
Questionretrieve webpage content,, such as image, video, etc Pin
ilmannafiah13-May-09 2:09
memberilmannafiah13-May-09 2:09 
Generalthank you guys for reading, but I will not be able to answer lots of questions related to specific platforms... Pin
liyang yu20-Feb-09 10:02
memberliyang yu20-Feb-09 10:02 
GeneralDetect UnNormal Disconnection Pin
g_s_p_200611-Feb-09 5:33
memberg_s_p_200611-Feb-09 5:33 
GeneralHelp needed Pin
cinnamom1-Feb-09 18:23
membercinnamom1-Feb-09 18:23 
Generalcin.getline() problem Pin
jvasher8-Nov-08 17:54
memberjvasher8-Nov-08 17:54 
QuestionWhy XPrecieveMessage? Pin
fangzj26-Aug-08 22:14
memberfangzj26-Aug-08 22:14 
GeneralConnections from the Desktop to the PDA.... Pin
Ansar-Ul-Haque Yasar17-Jul-08 6:25
memberAnsar-Ul-Haque Yasar17-Jul-08 6:25 
Generalfatal error C1083: Cannot open include file: '.....' Pin
Member 461962019-Apr-08 1:21
memberMember 461962019-Apr-08 1:21 
GeneralRe: fatal error C1083: Cannot open include file: '.....' Pin
Chinar27-Apr-08 18:12
memberChinar27-Apr-08 18:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.180111.1 | Last Updated 23 Jul 2004
Article Copyright 2004 by liyang yu
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid