Open In App

Design a concurrent server for handling multiple clients using fork()

Prerequisite: Socket Programming in C/C++, fork() System call 

Problem Statement: In this article, we are going to write a program that illustrates the Client-Server Model using fork() system call which can handle multiple clients concurrently. 



Fork() call creates multiple child processes for concurrent clients and runs each call block in its own process control block (PCB).

Need for designing a concurrent server for handling clients using fork() call:



Through TCP basic server-client model, one server attends only one client at a particular time.

But, we are now trying to make our TCP server handle more than one client. Although, we can achieve this using select() system call but we can ease the whole process.

How is the fork() system call going to help in this?

Fork() creates a new child process that runs in sync with its Parent process and returns 0 if child process is created successfully.

Difference from the other approaches:

This is the simplest technique for creating a concurrent server. Whenever a new client connects to the server, a fork() call is executed making a new child process for each new client.

Program to design a concurrent server for handling multiple clients using fork()




// Accept connection request from client in cliAddr
// socket structure
clientSocket = accept(
    sockfd, (struct sockaddr*)&cliAddr, &addr_size);
 
// Make a child process by fork() and check if child
// process is created successfully
if ((childpid = fork()) == 0) {
    // Send a confirmation message to the client for
    // successful connection
    send(clientSocket, "hi client", strlen("hi client"),
         0);
}




// Server side program that sends
// a 'hi client' message
// to every client concurrently
 
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
 
// PORT number
#define PORT 4444
 
int main()
{
    // Server socket id
    int sockfd, ret;
 
    // Server socket address structures
    struct sockaddr_in serverAddr;
 
    // Client socket id
    int clientSocket;
 
    // Client socket address structures
    struct sockaddr_in cliAddr;
 
    // Stores byte size of server socket address
    socklen_t addr_size;
 
    // Child process id
    pid_t childpid;
 
    // Creates a TCP socket id from IPV4 family
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
    // Error handling if socket id is not valid
    if (sockfd < 0) {
        printf("Error in connection.\n");
        exit(1);
    }
 
    printf("Server Socket is created.\n");
 
    // Initializing address structure with NULL
    memset(&serverAddr, '\0',
           sizeof(serverAddr));
 
    // Assign port number and IP address
    // to the socket created
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
 
    // 127.0.0.1 is a loopback address
    serverAddr.sin_addr.s_addr
        = inet_addr("127.0.0.1");
 
    // Binding the socket id with
    // the socket structure
    ret = bind(sockfd,
               (struct sockaddr*)&serverAddr,
               sizeof(serverAddr));
 
    // Error handling
    if (ret < 0) {
        printf("Error in binding.\n");
        exit(1);
    }
 
    // Listening for connections (upto 10)
    if (listen(sockfd, 10) == 0) {
        printf("Listening...\n\n");
    }
 
    int cnt = 0;
    while (1) {
 
        // Accept clients and
        // store their information in cliAddr
        clientSocket = accept(
            sockfd, (struct sockaddr*)&cliAddr,
            &addr_size);
 
        // Error handling
        if (clientSocket < 0) {
            exit(1);
        }
 
        // Displaying information of
        // connected client
        printf("Connection accepted from %s:%d\n",
               inet_ntoa(cliAddr.sin_addr),
               ntohs(cliAddr.sin_port));
 
        // Print number of clients
        // connected till now
        printf("Clients connected: %d\n\n",
               ++cnt);
 
        // Creates a child process
        if ((childpid = fork()) == 0) {
 
            // Closing the server socket id
            close(sockfd);
 
            // Send a confirmation message
            // to the client
            send(clientSocket, "hi client",
                 strlen("hi client"), 0);
        }
    }
 
    // Close the client socket id
    close(clientSocket);
    return 0;
}

 
 

 




// Client Side program to test
// the TCP server that returns
// a 'hi client' message
 
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
 
// PORT number
#define PORT 4444
 
int main()
{
    // Socket id
    int clientSocket, ret;
 
    // Client socket structure
    struct sockaddr_in cliAddr;
 
    // char array to store incoming message
    char buffer[1024];
 
    // Creating socket id
    clientSocket = socket(AF_INET,
                          SOCK_STREAM, 0);
 
    if (clientSocket < 0) {
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Client Socket is created.\n");
 
    // Initializing socket structure with NULL
    memset(&cliAddr, '\0', sizeof(cliAddr));
 
    // Initializing buffer array with NULL
    memset(buffer, '\0', sizeof(buffer));
 
    // Assigning port number and IP address
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
 
    // 127.0.0.1 is Loopback IP
    serverAddr.sin_addr.s_addr
        = inet_addr("127.0.0.1");
 
    // connect() to connect to the server
    ret = connect(clientSocket,
                  (struct sockaddr*)&serverAddr,
                  sizeof(serverAddr));
 
    if (ret < 0) {
        printf("Error in connection.\n");
        exit(1);
    }
 
    printf("Connected to Server.\n");
 
    while (1) {
 
        // recv() receives the message
        // from server and stores in buffer
        if (recv(clientSocket, buffer, 1024, 0)
            < 0) {
            printf("Error in receiving data.\n");
        }
 
        // Printing the message on screen
        else {
            printf("Server: %s\n", buffer);
            bzero(buffer, sizeof(buffer));
        }
    }
 
    return 0;
}

 

 

Compile script:

 

gcc server.c -o ser
   ./ser

gcc client.c -o cli
  ./cli

 

Output:

 

 

Advantages: The advantages of using this process are:

 

 

Disadvantages: The disadvantages are as mentioned here

 

 


Article Tags :