C Programming

How to Implement Multi-Processing Socket Server with Fork in C

A multi-processing socket server with fork in C allows us for concurrent handling of multiple client connections. By utilizing the fork system call, the server can create the child processes for each connected client which ensures the independent communication channels. This approach enables simultaneous communication with multiple clients.

Let us discuss about how to implement a multi-processing socket server with fork in C. We will explain about the programming examples of a server-side program and a client-side program by which we can achieve a multi-processing socket server with fork in C.

What Is the Fork System Call?

When a system call makes a clone of an existing process, it is called the “fork()” system call. It essentially splits the running program into two separate processes which are known as the parent and the child. All parameters are same for child and parent processes except that they have different PIDs. This system call returns the following:

  1. The PID of the child process to the parent
  2. Zero (0) to the child

Programming Example 1: Server-Side Program

#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>

#define PORT 8888

int main ()
{
    int serSoc, cliSoc ;
    struct sockaddr_in serverAddr, clientAddr;
    socklen_t addrSize = sizeof (clientAddr);
    char buffer [1024];
    int clientCount = 0;

    // Create server socket
    serSoc = socket(AF_INET, SOCK_STREAM, 0);
    if (serSoc < 0) {
        perror ("Error in socket creation");
        exit (1);
    }

    printf ("Server socket created.\n");

    // let us Set server address
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons (PORT);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

   
    if (bind(serSoc, (struct sockaddr*) & serverAddr, sizeof (serverAddr)) < 0) {
        perror ("Error in binding");
        exit (1);
    }

    // Start listening for incoming connections
    if (listen (serSoc, 5) == 0) {
        printf ("Listening for connections...\n");
    } else {
        perror ("Error in listening");
        exit (1);
    }

    while (1) {
        // Let us  Accept for a  client connection
        cliSoc  = accept (serSoc, (struct sockaddr* )& clientAddr, &addrSize);
        if (cliSoc  < 0) {
            perror("Error in accepting connection");
            exit (1);
        }

        // Increment the client count and display client information

        clientCount++;
        printf("Accepted connection from Client %d: %s:%d\n", clientCount, inet_ntoa (clientAddr.sin_addr), ntohs (clientAddr.sin_port));
        printf ("Total clients connected: %d\n", clientCount);

       
        pid_t pid = fork ();

        if (pid == 0) {
            // Child process

           
            close (serSoc);

            // Receive messages from the client
            while (1) {
                memset (buffer, 0, sizeof(buffer));
                if (recv (cliSoc , buffer, sizeof (buffer), 0) < 0) {
                    perror ("Error in receiving data");
                    exit(1);
                }

                printf ("Received data from Client %d: %s\n", clientCount, buffer);

                // Echo the received message back to the client
                if (send (cliSoc , buffer, strlen (buffer), 0)  0) {
            // Parent process

           
            close(cliSoc );
        } else {
            perror ("Error in forking");
            exit (1);
        }
    }

    // Close the server socket
    close (serSoc);

    return 0;
}

Programming Example 2: Client-Side Program

#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>
#define PORT 8888
#define SERVER_IP "127.0.0.1"

int main ()
{
    int cliSoc ;
    struct sockaddr_in serverAddr;
    char buffer [1024];
    // Create client socket
    cliSoc  = socket (AF_INET, SOCK_STREAM, 0);
    if (cliSoc  < 0) {
        perror ("Error in socket creation");
        exit (1);
    }

    printf("Client %d socket created.\n", getpid ());

    // Set server address parameters
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons (PORT);
    serverAddr.sin_addr.s_addr = inet_addr (SERVER_IP);
    // Connect to the server
    if (connect (cliSoc , (struct sockaddr*) & serverAddr, sizeof (serverAddr)) < 0) {
        perror("Error in connecting to server");
        exit (1);
    }

    printf ("Connected to server.\n");
    while (1) {
        // Read input from user
        printf ("Client %d - Enter a message: ", getpid ());
        fgets (buffer, sizeof(buffer), stdin);

       
        if (send (cliSoc , buffer, strlen (buffer), 0) < 0) {
            perror ("Error in sending data");
            exit (1);

        }
        // Receive response from the server
        memset (buffer, 0, sizeof(buffer));
        if (recv (cliSoc , buffer, sizeof (buffer), 0) < 0) {
            perror ("Error in receiving data");
            exit (1);
        }
        printf ("Client %d - Server response: %s\n", getpid (), buffer);
    }

    // Close the client socket
    close (cliSoc );
    return 0;
}

Output:

**Server program compilation**
$ gcc ser.c -o ser
$ ./ser
Server socket created.
Listening for connections...
Server socket created.
Listening for connections...
Accepted connection from Client 1: 127.0.0.1:59074
Total clients connected: 1
Received data from Client 1: hii admin
Accepted connection from Client 2: 127.0.0.1:40192
Total clients connected: 2
Received data from Client 2: hello everybody
**Client 1 program compilation**
$ gcc cel.c -o cel
$ ./cel
Client 4007 socket created.
Connected to server.
Client 4007 - Enter a message: hii admin

**Client 2 program compilation**
$ gcc cel.c -o cel
$ ./cel
Client 4024 socket created.
Connected to server.
Client 4024 - Enter a message: hello everybody

Explanation:

In this programming example, we explained the implementation of a multi-processing socket server with fork in C. Here in the server-side program, we create a server socket, bind it to a specific address and port, and listen for incoming connections. When a client connects, a child process is created using “fork()”. This allows the concurrent handling of multiple clients. The child process receives the messages from the client and displays the data with the client’s ID. This multi-processing socket server allows us for simultaneous communication with “n” number of clients.

Conclusion

We discussed about the implementation of a multi-processing socket server with fork in C. Using the fork system call, this allows us for concurrent handling of multiple client connections. This enables simultaneous communication with multiple clients and efficient handling of client requests.

About the author

Bamdeb Ghosh

Bamdeb Ghosh is having hands-on experience in Wireless networking domain.He's an expert in Wireshark capture analysis on Wireless or Wired Networking along with knowledge of Android, Bluetooth, Linux commands and python. Follow his site: wifisharks.com