Linux C++ Forking Server and Client Socket Example

Aim
The goal of this example is to create simple Linux C++ server that accepts socket connections and forks-off to handle the connection. This is the simplest Linux C++ forking server socket and client example you can find. This covers all the steps required to open a C++ client/server socket and forking a process. Please leave any comments or questions at the end of this tutorial and I will endeavour to answer them. This tutorial shares the client code with Linux C++ Socket Example with Client Server and Mulit-Threading .

Assumptions
This article assumes that you have a Linux based C++ compiler installed and configured. You can use cygwin if you do not have a Linux environment.

Versions used in this example
Sofware/ComponentImage
Fedora Core 5N/A
Links to these files can be found here

You can download the zipped example here.

Steps required for a server socket
  1. Initialize the socket using socket().
  2. Set any options such as blocking etc using setsockopt().
  3. Bind to the local address and port using bind(). For a server use INADDR_ANY as the address.
  4. listen() for connections.
  5. Go into a loop and accept connections usin accept().
  6. fork! handle the connection in the child process and go back to listening for another socket in the parent process
  7. Read and write to the socket. within the thread.
  8. close()
  9. When you are done, close the server socket using close()

Steps required for a client socket
    Please see the Linux C++ Socket Example with Client Server and Mulit-Threading tutorial for the client.

Write and compile the Server
  1. The server listens on port 1101 for a connection. When it receives a connection it creates a thread via pthread_create 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 LinSever.cpp.
     1. #include <fcntl.h>
     2. #include <string.h>
     3. #include <stdlib.h>
     4. #include <errno.h>
     5. #include <stdio.h>
     6. #include <netinet/in.h>
     7. #include <resolv.h>
     8. #include <sys/socket.h>
     9. #include <arpa/inet.h>
    10. #include <unistd.h>
    11. #include <pthread.h>
    12. 
    13. void* SocketHandler(void*);
    14. 
    15. int main(int argv, char** argc){
    16. 
    17.     int host_port= 1101;
    18. 
    19.     struct sockaddr_in my_addr;
    20. 
    21.     int hsock;
    22.     int * p_int ;
    23.     int err;
    24. 
    25.     socklen_t addr_size = 0;
    26.     int* csock;
    27.     sockaddr_in sadr;
    28.     pthread_t thread_id=0;
    29. 
    30.     int childpid;
    31. 
    32.     signal(SIGCHLD, SIG_IGN);
    33. 
    34.     hsock = socket(AF_INET, SOCK_STREAM, 0);
    35.     if(hsock == -1){
    36.         printf("Error initializing socket %d\n", errno);
    37.         goto FINISH;
    38.     }
    39.     
    40.     p_int = (int*)malloc(sizeof(int));
    41.     *p_int = 1;
    42.         
    43.     if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
    44.         (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
    45.         printf("Error setting options %d\n", errno);
    46.         free(p_int);
    47.         goto FINISH;
    48.     }
    49.     free(p_int);
    50. 
    51. 
    52.     my_addr.sin_family = AF_INET ;
    53.     my_addr.sin_port = htons(host_port);
    54.     
    55.     memset(&(my_addr.sin_zero), 0, 8);
    56.     my_addr.sin_addr.s_addr = INADDR_ANY ;
    57.     
    58.     if( bind( hsock, (sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
    59.         fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",errno);
    60.         goto FINISH;
    61.     }
    62.     if(listen( hsock, 10) == -1 ){
    63.         fprintf(stderr, "Error listening %d\n",errno);
    64.         goto FINISH;
    65.     }
    66. 
    67.     //Now lets do the server stuff
    68. 
    69.     addr_size = sizeof(sockaddr_in);
    70.     
    71.     while(true){
    72.         printf("waiting for a connection\n");
    73.         csock = (int*)malloc(sizeof(int));
    74.         if((*csock = accept( hsock, (sockaddr*)&sadr, &addr_size))!= -1){
    75.             printf("---------------------\nReceived connection from %s\n",inet_ntoa(sadr.sin_addr));
    76.             switch( childpid=fork()){
    77.                 case -1://error
    78.                     fprintf(stderr, "Error spawning the child %d\n",errno);
    79.                     exit(0);
    80.                     break;
    81.                 case 0://in the child
    82.                     SocketHandler(csock);
    83.                     exit(0);
    84.                 default://in the server
    85.                     close(*csock);
    86.                     free(csock);
    87.                     break;
    88.             }
    89.         }
    90.         else{
    91.             fprintf(stderr, "Error accepting %d\n", errno);
    92.         }
    93.     }
    94.     
    95. FINISH:
    96. ;
    97. }
    98. 
    99. void* SocketHandler(void* lp){
    100.     int *csock = (int*)lp;
    101. 
    102.     char buffer[1024];
    103.     int buffer_len = 1024;
    104.     int bytecount;
    105. 
    106.     memset(buffer, 0, buffer_len);
    107.     if((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){
    108.         fprintf(stderr, "Error receiving data %d\n", errno);
    109.         goto FINISH;
    110.     }
    111.     printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
    112.     strcat(buffer, " SERVER ECHO");
    113. 
    114.     if((bytecount = send(*csock, buffer, strlen(buffer), 0))== -1){
    115.         fprintf(stderr, "Error sending data %d\n", errno);
    116.         goto FINISH;
    117.     }
    118.     
    119.     printf("Sent bytes %d\n", bytecount);
    120. 
    121. 
    122. FINISH:
    123.     free(csock);
    124.     return 0;
    125. }
    Hide line numbers

    Line 32: When a child process exits without a call to 'wait()' from the parent, it turns into a 'zombie.' You can prevent this by setting signal(SIGCHLD, SIG_IGN);

    Line 76: Fork returns -1 in the parent on failure. It return the child pid in the parent and 0 in the child.

    Line 85: When you fork, you must close the client connection in the parent(server) process, otherwise you will hit the "open socket descriptor limit" in Linux.
  2. `
  3. Open a prompt to the working directory and compile the code using your C++ compiler

    ..workspace\SocketExample>g++ -o server LinServer.cpp -lpthread

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. You can view the client in this tutorial Linux C++ Socket Example with Client Server and Mulit-Threading .


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

    ..workspace\SocketExample>server

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

    ..workspace\SocketExample>client

  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.

6 comments:

Mike said...

Adding:

#include

fixed any compiles I was getting.

Viktor said...

It looks like the child process after returning from call SocketHandler(csock) (line 81) will return to the start of loop and try accept the connection.

Another issue - if hsock will get due to some reason closed, the program will get into endless loop, eating all process resources.

righteous said...

Good stuff. Yes, the client won't quit and if there is an error it will go into an endless loop. Fixed by exiting instead of break and quitting the loop on hsock error.

I should take more care when creating demons.

Thanks again.

Anonymous said...

goto??!! :):)

Naviya Nair said...

Very interesting and good Explanation
ASP NET Training
ASP NET Training
ASP NET Online Training
C-Sharp Training
Dot Net Training in Chennai
Online .Net Training


MVC Training
WCF Training
Web-API Training
LINQ Training
Entity Framework
Training

Dot Net Interview Questions

Nickotronz7 said...

there's any way to run it on clion?