Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Parallel TCP/IP Socket Server With Multithreading and Multiprocessing in C

DZone's Guide to

Parallel TCP/IP Socket Server With Multithreading and Multiprocessing in C

Learn how to use the C language to use a TCP/IP server to receive multiple client requests at the same time and run each client request in parallel.

Free Resource

SnapLogic is the leading self-service enterprise-grade integration platform. Download the 2018 GartnerMagic Quadrant for Enterprise iPaaS or play around on the platform, risk free, for 30 days.

The primary intention of writing this article is to give you an overview of how we can entertain multiple client requests to a server in parallel. For example, you are going to create a TCP/IP server which can receive multiple client requests at the same time and entertain each client request in parallel so that no client will have to wait for server time. Normally, you will get lots of examples of TCP/IP servers and client examples online which are not capable of processing multiple client requests in parallel.  

In the first example, the TCP/IP server has been designed with multi-threading for parallel processing and in the second example, I have implemented the server with multi-processing to accomplish the same goal. 

Below is the server application (in C). Here I have created a function called socketThreadwhich is a thread function. Whenever a request comes to the server, the server’s main thread will create a thread and pass the client request to that thread with its ID. The thread will start processing with the client request, generate the report, and send it back to the client. As this is just an example, you need to put your own business logic in the thread function. I have just put a sleep statement here and am sending a hard-coded reply from the server to the client. This is just a very simple example and not a professional based TCP/IP server.  

The second program is a sample client to test this server. Both of these programs are for Unix/Linux environments only. 

socket_server.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include<pthread.h>

char client_message[2000];
char buffer[1024];
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void * socketThread(void *arg)
{
  int newSocket = *((int *)arg);
  recv(newSocket , client_message , 2000 , 0);

  // Send message to the client socket 
  pthread_mutex_lock(&lock);
  char *message = malloc(sizeof(client_message)+20);
  strcpy(message,"Hello Client : ");
  strcat(message,client_message);
  strcat(message,"\n");
  strcpy(buffer,message);
  free(message);
  pthread_mutex_unlock(&lock);
  sleep(1);
  send(newSocket,buffer,13,0);
  printf("Exit socketThread \n");
  close(newSocket);
  pthread_exit(NULL);
}

int main(){
  int serverSocket, newSocket;
  struct sockaddr_in serverAddr;
  struct sockaddr_storage serverStorage;
  socklen_t addr_size;

  //Create the socket. 
  serverSocket = socket(PF_INET, SOCK_STREAM, 0);

  // Configure settings of the server address struct
  // Address family = Internet 
  serverAddr.sin_family = AF_INET;

  //Set port number, using htons function to use proper byte order 
  serverAddr.sin_port = htons(7799);

  //Set IP address to localhost 
  serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");


  //Set all bits of the padding field to 0 
  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);

  //Bind the address struct to the socket 
  bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));

  //Listen on the socket, with 40 max connection requests queued 
  if(listen(serverSocket,50)==0)
    printf("Listening\n");
  else
    printf("Error\n");
    pthread_t tid[60];
    int i = 0;
    while(1)
    {
        //Accept call creates a new socket for the incoming connection
        addr_size = sizeof serverStorage;
        newSocket = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size);

        //for each client request creates a thread and assign the client request to it to process
       //so the main thread can entertain next request
        if( pthread_create(&tid[i], NULL, socketThread, &newSocket) != 0 )
           printf("Failed to create thread\n");

        if( i >= 50)
        {
          i = 0;
          while(i < 50)
          {
            pthread_join(tid[i++],NULL);
          }
          i = 0;
        }
    }
  return 0;
}

This is an example of a simple multithreaded client for testing with 50 parallel requests to the server. If you want to test the client from a different machine, change the localhost to the actual server host and port number.

socket_client.c

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include<pthread.h>

void * cientThread(void *arg)
{
  printf("In thread\n");
  char message[1000];
  char buffer[1024];
  int clientSocket;
  struct sockaddr_in serverAddr;
  socklen_t addr_size;

  // Create the socket. 
  clientSocket = socket(PF_INET, SOCK_STREAM, 0);

  //Configure settings of the server address
 // Address family is Internet 
  serverAddr.sin_family = AF_INET;

  //Set port number, using htons function 
  serverAddr.sin_port = htons(7799);

 //Set IP address to localhost
  serverAddr.sin_addr.s_addr = inet_addr("localhost");
  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);

    //Connect the socket to the server using the address
    addr_size = sizeof serverAddr;
    connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
    strcpy(message,"Hello");

   if( send(clientSocket , message , strlen(message) , 0) < 0)
    {
            printf("Send failed\n");
    }

    //Read the message from the server into the buffer
    if(recv(clientSocket, buffer, 1024, 0) < 0)
    {
       printf("Receive failed\n");
    }
    //Print the received message
    printf("Data received: %s\n",buffer);
    close(clientSocket);
    pthread_exit(NULL);
}
int main(){
  int i = 0;
  pthread_t tid[51];
  while(i< 50)
  {
    if( pthread_create(&tid[i], NULL, cientThread, NULL) != 0 )
           printf("Failed to create thread\n");
    i++;
  }
  sleep(20);
  i = 0;
  while(i< 50)
  {
     pthread_join(tid[i++],NULL);
     printf("%d:\n",i);
  }
  return 0;
}

Compile both the client and the server in Linux or in Unix like below:

  •  cc socket_client.c -o client -lsocket -lnsl 

  • cc socket_server.c -o server -lsocket –lnsl  

First, run the server and then run the client from a different terminal (better to run both from different machines). When you run the client from a different Linux/Unix server, please consider the firewall issues. 

Now, below, is the server design with a multi-process approach for parallel processing. Here I am using the same function and calling it from a child process. In the previous example, the same process was called from a child thread. 

socket_server.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <sys/types.h>

void  socketThread(int  clientSocket)
{
   char client_message[2000];
   char buffer[1024];

  int newSocket = clientSocket;
  recv(newSocket , client_message , 2000 , 0);

  // Send message to the client socket 
  char *message = malloc(sizeof(client_message)+20);
  strcpy(message,"Hello Client : ");
  strcat(message,client_message);
  strcat(message,"\n");
  strcpy(buffer,message);
  free(message);
  pthread_mutex_unlock(&lock);
  sleep(1);
  send(newSocket,buffer,13,0);
  printf("Exit socketThread \n");
  close(newSocket);
  }

int main(){
  int serverSocket, newSocket;
  struct sockaddr_in serverAddr;
  struct sockaddr_storage serverStorage;
  socklen_t addr_size;
  pid_t pid[50];
  //Create the socket. 
  serverSocket = socket(PF_INET, SOCK_STREAM, 0);

  // Configure settings of the server address struct
  // Address family = Internet 
  serverAddr.sin_family = AF_INET;

  //Set port number, using htons function to use proper byte order 
  serverAddr.sin_port = htons(7799);

  //Set IP address to localhost 
  serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");


  //Set all bits of the padding field to 0 
  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);

  //Bind the address struct to the socket 
  bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));

  //Listen on the socket, with 40 max connection requests queued 
  if(listen(serverSocket,50)==0)
    printf("Listening\n");
  else
    printf("Error\n");
    pthread_t tid[60];
    int i = 0;
while(1)
    {
        /*---- Accept call creates a new socket for the incoming connection ----*/
        addr_size = sizeof serverStorage;
        newSocket = (serverSocket, (struct sockaddr *) &serverStorage, &addr_size);
        int pid_c = 0;

      if ((pid_c = fork())==0)
        {
          socketThread(newSocket);
        }
        else
        {
          pid[i++] = pid_c;
          if( i >= 49)
           {
             i = 0;
             while(i < 50)
                waitpid(pid[i++], NULL, 0);
             i = 0;
           }
        }
    }
  return 0;
}

With SnapLogic’s integration platform you can save millions of dollars, increase integrator productivity by 5X, and reduce integration time to value by 90%. Sign up for our risk-free 30-day trial!

Topics:
tcp/ip ,socket programming ,multi-threaded server ,parallel computing ,integration ,forking ,socket communicaiton ,client ,server

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}