Windows C++ Socket Example Using Client Server and Multi-Threading

Aim
The aim of this C++ tutorial is to demonstrate simple client/server socket communication and multi-threading on Windows. This demonstrates basics such as binding, listening and accepting sockets for Servers and connecting sockets for clients. Once the server accepts a socket, a thread is spawned to handle it. This is the simplest Windows C++ socket (blocking) example you can find. Please leave any comments or questions at the end of this tutorial and I will endeavour to answer them.

Assumptions
This article assumes that you have VC++ installed and configured. See Problems and Solutions Installing VC++ Express Edition, to install and run vcvars32.bat.

Versions used in this example
Sofware/ComponentImage
Windows XP SP2N/A
Visual Studio Express Editions 2008 VC++N/A
Links to these files can be found here

You can download the zipped example here.

Steps required for a server socket
  1. Use WSAStartup() to initialize socket support. You only need this for VC++
  2. Initialize the socket using socket().
  3. Set any options such as blocking etc using setsockop().
  4. Bind to the local address and port using bind(). For a server use INADDR_ANY as the address.
  5. listen() for connections.
  6. Go into a loop and accept connections usin accept(). Spawn threads to handle these connections, so you can accept more connections.
    • Read and write to the socket. within the thread.
    • closesocket()
      • When you are done, close the server socket using closesocket()

      Steps required for a client socket
      1. Use WSAStartup() to initialize socket support. You only need this for VC++
      2. Initialize the socket using socket().
      3. Set any options such as blocking etc using setsockop().
      4. Connect to the remote host using connet(). Supply address and port here.
      5. Read and write to the socket. closesocket()

      Write and compile the Server
      1. The server listens for a connection. When it receives a connection it spawns a tread to handle it. This thread then reads from the socket, appends " SERVER ECHO" to it and sends it back to the client. As the server doesn't require an IP address, we assign INADDR_ANY to the sockaddr_in struct. Save this code as WinSever.cpp.
         1. #include <winsock2.h>
         2. #include <windows.h>
         3. #include <fcntl.h>
         4. #include <string.h>
         5. #include <stdlib.h>
         6. #include <errno.h>
         7. #include <stdio.h>
         8. 
         9. DWORD WINAPI SocketHandler(void*);
        10. 
        11. int main(int argv, char** argc){
        12. 
        13.     //The port you want the server to listen on
        14.     int host_port= 1101;
        15. 
        16.     //Initialize socket support WINDOWS ONLY!
        17.     unsigned short wVersionRequested;
        18.     WSADATA wsaData;
        19.     int err;
        20.     wVersionRequested = MAKEWORD( 2, 2 );
        21.      err = WSAStartup( wVersionRequested, &wsaData );
        22.     if ( err != 0 || ( LOBYTE( wsaData.wVersion ) != 2 ||
        23.             HIBYTE( wsaData.wVersion ) != 2 )) {
        24.         fprintf(stderr, "Could not find useable sock dll %d\n",WSAGetLastError());
        25.         goto FINISH;
        26.     }
        27. 
        28.     //Initialize sockets and set any options
        29.     int hsock;
        30.     int * p_int ;
        31.     hsock = socket(AF_INET, SOCK_STREAM, 0);
        32.     if(hsock == -1){
        33.         printf("Error initializing socket %d\n",WSAGetLastError());
        34.         goto FINISH;
        35.     }
        36.     
        37.     p_int = (int*)malloc(sizeof(int));
        38.     *p_int = 1;
        39.     if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
        40.         (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
        41.         printf("Error setting options %d\n", WSAGetLastError());
        42.         free(p_int);
        43.         goto FINISH;
        44.     }
        45.     free(p_int);
        46. 
        47.     //Bind and listen
        48.     struct sockaddr_in my_addr;
        49. 
        50.     my_addr.sin_family = AF_INET ;
        51.     my_addr.sin_port = htons(host_port);
        52.     
        53.     memset(&(my_addr.sin_zero), 0, 8);
        54.     my_addr.sin_addr.s_addr = INADDR_ANY ;
        55.     
        56.     if( bind( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
        57.         fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",WSAGetLastError());
        58.         goto FINISH;
        59.     }
        60.     if(listen( hsock, 10) == -1 ){
        61.         fprintf(stderr, "Error listening %d\n",WSAGetLastError());
        62.         goto FINISH;
        63.     }
        64.     
        65.     //Now lets to the server stuff
        66. 
        67.     int* csock;
        68.     sockaddr_in sadr;
        69.     int    addr_size = sizeof(SOCKADDR);
        70.     
        71.     while(true){
        72.         printf("waiting for a connection\n");
        73.         csock = (int*)malloc(sizeof(int));
        74.         
        75.         if((*csock = accept( hsock, (SOCKADDR*)&sadr, &addr_size))!= INVALID_SOCKET ){
        76.             printf("Received connection from %s",inet_ntoa(sadr.sin_addr));
        77.             CreateThread(0,0,&SocketHandler, (void*)csock , 0,0);
        78.         }
        79.         else{
        80.             fprintf(stderr, "Error accepting %d\n",WSAGetLastError());
        81.         }
        82.     }
        83. 
        84. FINISH:
        85. ;
        86. }
        87. 
        88. DWORD WINAPI SocketHandler(void* lp){
        89.     int *csock = (int*)lp;
        90. 
        91.     char buffer[1024];
        92.     int buffer_len = 1024;
        93.     int bytecount;
        94. 
        95.     memset(buffer, 0, buffer_len);
        96.     if((bytecount = recv(*csock, buffer, buffer_len, 0))==SOCKET_ERROR){
        97.         fprintf(stderr, "Error receiving data %d\n", WSAGetLastError());
        98.         goto FINISH;
        99.     }
        100.     printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
        101.     strcat(buffer, " SERVER ECHO");
        102. 
        103.     if((bytecount = send(*csock, buffer, strlen(buffer), 0))==SOCKET_ERROR){
        104.         fprintf(stderr, "Error sending data %d\n", WSAGetLastError());
        105.         goto FINISH;
        106.     }
        107.     
        108.     printf("Sent bytes %d\n", bytecount);
        109. 
        110. 
        111. FINISH:
        112.     free(csock);
        113.     return 0;
        114. }
        Hide line numbers
      2. Open a prompt to the working directory and compile the code using the windows cl.exe compiler. You just need to include the ws2_2.lib.

        ..workspace\SocketExample>cl WinServer.cpp ws2_32.lib.lib

      Write and compile the Client
      1. The client reads a line from the console and sends this to the server. It then reads from the server and displays it on the console. Save this code as WinClient.cpp.
         1. #include <winsock2.h>
         2. #include <windows.h>
         3. #include <fcntl.h>
         4. #include <string.h>
         5. #include <stdlib.h>
         6. #include <errno.h>
         7. #include <stdio.h>
         8. #include <conio.h>
         9. 
        10. int main(int argv, char** argc){
        11. 
        12.     //The port and address you want to connect to
        13.     int host_port= 1101;
        14.     char* host_name="127.0.0.1";
        15. 
        16.     //Initialize socket support WINDOWS ONLY!
        17.     unsigned short wVersionRequested;
        18.     WSADATA wsaData;
        19.     int err;
        20.     wVersionRequested = MAKEWORD( 2, 2 );
        21.      err = WSAStartup( wVersionRequested, &wsaData );
        22.     if ( err != 0 || ( LOBYTE( wsaData.wVersion ) != 2 ||
        23.             HIBYTE( wsaData.wVersion ) != 2 )) {
        24.         fprintf(stderr, "Could not find useable sock dll %d\n",WSAGetLastError());
        25.         goto FINISH;
        26.     }
        27. 
        28.     //Initialize sockets and set any options
        29.     int hsock;
        30.     int * p_int ;
        31.     hsock = socket(AF_INET, SOCK_STREAM, 0);
        32.     if(hsock == -1){
        33.         printf("Error initializing socket %d\n",WSAGetLastError());
        34.         goto FINISH;
        35.     }
        36.     
        37.     p_int = (int*)malloc(sizeof(int));
        38.     *p_int = 1;
        39.     if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
        40.         (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
        41.         printf("Error setting options %d\n", WSAGetLastError());
        42.         free(p_int);
        43.         goto FINISH;
        44.     }
        45.     free(p_int);
        46. 
        47.     //Connect to the server
        48.     struct sockaddr_in my_addr;
        49. 
        50.     my_addr.sin_family = AF_INET ;
        51.     my_addr.sin_port = htons(host_port);
        52.     
        53.     memset(&(my_addr.sin_zero), 0, 8);
        54.     my_addr.sin_addr.s_addr = inet_addr(host_name);
        55. 
        56. 
        57.     if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == SOCKET_ERROR ){
        58.         fprintf(stderr, "Error connecting socket %d\n", WSAGetLastError());
        59.         goto FINISH;
        60.     }
        61. 
        62.     //Now lets do the client related stuff
        63. 
        64.     char buffer[1024];
        65.     int buffer_len = 1024;
        66.     int bytecount;
        67.     
        68.     int c;
        69.     memset(buffer, '\0', buffer_len);
        70. 
        71.     for(char* p=buffer ; (c=getch())!=13 ; p++){
        72.         printf("%c", c);
        73.         *p = c;
        74.     }
        75.     
        76.     if( (bytecount=send(hsock, buffer, strlen(buffer),0))==SOCKET_ERROR){
        77.         fprintf(stderr, "Error sending data %d\n", WSAGetLastError());
        78.         goto FINISH;
        79.     }
        80.     printf("Sent bytes %d\n", bytecount);
        81. 
        82.     if((bytecount = recv(hsock, buffer, buffer_len, 0))==SOCKET_ERROR){
        83.         fprintf(stderr, "Error receiving data %d\n", WSAGetLastError());
        84.         goto FINISH;
        85.     }
        86.     printf("Recieved bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
        87. 
        88.     closesocket(hsock);
        89.     
        90. FINISH:
        91. ;
        92. }
        Hide line numbers

      2. Open a prompt to the working directory and compile the code using the windows cl.exe compiler. You just need to include the ws2_2.lib.

        ..workspace\SocketExample>cl WinClient.cpp ws2_32.lib.lib


      Run the example
      1. Open a prompt to the working directory and run the server.

        ..workspace\SocketExample>WinServer.exe

      2. Open another prompt to the working directory and run the Client.

        ..workspace\SocketExample>WinClient.exe

      3. Now type something into the client prompt and press ENTER.
      4. You will see the exchange between client and server. You can open many client prompts at the same time and test.

      21 comments:

      genux said...

      Great stuff. Have you done anything with windows services ? so that you can run them in services that "talk" to each other from one computer to another ?

      very cool :)

      C++ Code Snippets said...

      Great tutorial, thanks for it.

      Ajay Kumar Singh said...

      Very nice !! I appreciate.
      Have u done to communicate client from another Pc on same network ?

      syafiqahderani said...

      hye..
      i don't know y i can't build your project at all..
      can u please help me..?
      i'm using visual studio C++ express version 2010...

      can u please email me at ieqa4409@gmail.com

      i can email u the list of error that i have. tq..

      Halley said...

      Great help, thank you.

      I'm just having trouble running it on the command prompt. I have VC++ 2010 and it seems like the command to compile it is different for 2010? It says that cl is not recognized as an internal or external command.

      Is that because the compiler for VC++ 2010 is different or am I just not doing something right?

      Thank you again

      Halley said...

      ***UPDATE***

      I got to make that work, however now I get a different msg that says: "LINK: fatal error LNK1181: cannot open input file 'ws_32.lib.lib'"

      Sorry if I'm making a stupid mistake, I'm just getting used to C++ and VC++ 2010.

      Anonymous said...

      use 'ws2_32.lib' under Linker/Input/Additional Dependencies

      Anonymous said...

      video tutorial about c++: dll, compiling, linking, import library, porting, and extending:
      http://msdn.microsoft.com/en-us/visualc/video/Bb838687

      notes about DDL:
      http://msdn.microsoft.com/en-us/library/1ez7dh12.aspx

      Anonymous said...

      On the following problem:
      -----------------
      I got to make that work, however now I get a different msg that says: "LINK: fatal error LNK1181: cannot open input file 'ws_32.lib.lib'"

      Sorry if I'm making a stupid mistake, I'm just getting used to C++ and VC++ 2010.
      -----------------

      The solution is simple. Just add this line after the header files:

      #pragma comment (lib, "Ws2_32.lib")

      This will work just fine!

      Alican said...

      I made a similar client/server program using multi-threading, however, I can't send message from one client to another through the server has anyone got an idea.

      jeffreytk said...

      Excellent winsock example!

      Alican, the example server has the client data received in local data to that thread. You will have to create a data structure each server thread can read/write to.

      Also, you will have to change the SocketHandler's reading/writing.

      Right now it blocks on getting something to read, then writes it, and closes the thread.

      You want to loop on these things:

      -"see if there's anything to read" from your client (from the view of this instance of a thread) (and if you do read something, put it in the shared data object.)

      -sending anything to your client that's new in the shared data object (stuff from the other client).

      Anonymous said...

      My system: Code::Blocks with MinGW

      I got a compile error:

      sockaddr_in undeclared

      even when I have included winsock2.h before windows.h, recently I compile another sockets examples and worked OK.

      Anonymous said...

      I found a solution:

      http://sourceforge.net/mailarchive/forum.php?thread_name=E1NlmJw-0002iv-VF%40sfs-web-9.v29.ch3.sourceforge.com&forum_name=mingw-notify

      winsock2.h needed some edition!

      Anonymous said...

      How make an event like onReceive at CSocket on client side? It means that when the server side has newer data, it will send the newer data to client side. Thanks.

      Anonymous said...

      stop telling people to use goto. there are MANY, MANY good alternatives for every single goto you're using in this example code. you are teaching horrible habits and you should probably go back and re-learn proper software design practices before trying to teach others.

      execNext.com said...

      Actually, 'Anonymous', the most horrible habit is to take a rule-of-thumb and make it an absolute. I have found two excellent uses for the goto statement:

      1) to continue or break from nested loops in languages that do not have labelled loops and labelled breaks and continues.

      2) to provide a single exit point from a function, which both a) guarantees my log.fctExit() routine is always called before returning, and b) keeps the nesting level of the algorithm minimal.

      The modern priority code formatting heuristic is to improve readability and without goto FINISH (or goto ex, as I prefer :-) you get a tangle of if-else-if-else's. By checking for failure after each 'failable' operation, then gotoing out on such cases, the code reads linearly just as the algorithm is supposed to.

      Such readability is especially crucial in C and C++ where both syntax errors and semantic errors are both easy to produce and occasionally wicked to fix.

      Remember (IIRC): programmers spend 3x as much modifying their code as writing new code and 5x as much time reading their code as modifying it.

      Peace be with you all,
      Robert McCall
      execNext.com
      DONE := "Lasting peace and happiness for *ALL* human beings."

      Anonymous said...

      The server example does not compile for me: error line 69 (the goto) crosses initialization of int addr_size

      righteous said...

      Cut the line in 69 and stick it somewhere at the top. Actually cut all three lines...

      67. int* csock;
      68. sockaddr_in sadr;
      69. int addr_size = sizeof(SOCKADDR);

      and paste them at the top of the function.

      Anonymous said...

      There's a typo in the explanation where is says "You just need to include the ws2_2.lib".

      Milon said...
      This comment has been removed by the author.
      Milon said...

      thank you very much. Its really help full. As far i understand this code is for sending messages from multiple client to single server. the server only send echo to that client from where it receive message.
      can you tell me how to make it client to client communication? like if a client send any message then it will broadcast to all client.
      Can i limit the number of client here?
      i really appreciate your concern in it.
      thank you