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:
- The PID of the child process to the parent
- Zero (0) to the child
Programming Example 1: Server-Side Program
#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 <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:
$ 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.