Creating Server Script

In this section, we will create the server script in C language. So follow the steps and break down the script to understand the implementation of the server.

Step 1: Create a server.c File

Firstly, create the server.c file in the nano editor by using the command in the terminal.

nano server.c

Creating server.c file

Step 2: Server Initialization and Socket Binding

C




int serverSocket;
struct sockaddr_in serverAddr;
char buffer[MAX_MESSAGE_SIZE];
socklen_t clientLen = sizeof(struct sockaddr_in);
ssize_t bytesRead;
 
// Create socket
if ((serverSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    perror("Socket creation failed");
    exit(EXIT_FAILURE);
}
 
// Configure server address
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(PORT);
 
// Bind socket
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
    perror("Bind failed");
    exit(EXIT_FAILURE);
}
 
// Initialize mutex
pthread_mutex_init(&mutex, NULL);
 
printf("Server listening on port %d...\n", PORT);


  • Socket Creation: The server uses the socket system call to create a UDP socket.
  • Server Address Configuration: The server’s address structure (serverAddr) is configured with the server’s IP, port, and protocol details.
  • Binding: The socket is bound to the server’s address using the bind system call.
  • Mutex Initialization: A mutex (pthread_mutex_t mutex) is initialized for thread synchronization.
  • Print Server Listening: A message is printed indicating that the server is listening on a specific port.

Step 3: Handling Clients – Main Loop

C




// Create a thread for each client
while (1) {
    // Receive message from client
    bytesRead = recvfrom(serverSocket, buffer, sizeof(buffer), 0, (struct sockaddr*)&clients[clientCount].address, &clientLen);
    if (bytesRead == -1) {
        perror("Receive failed");
        exit(EXIT_FAILURE);
    }
 
    buffer[bytesRead] = '\0';
    printf("Client %d connected: %s", clientCount + 1, buffer);
 
    // Add client to the list
    clients[clientCount].socket = serverSocket;
    clients[clientCount].id = clientCount;
    pthread_create(&threads[clientCount], NULL, handleClient, (void*)&clients[clientCount].id);
    clientCount++;
 
    // Send a welcome message to the client (for demonstration purposes)
    sprintf(buffer, "Server: Welcome, you are Client %d\n", clientCount);
    sendto(clients[clientCount - 1].socket, buffer, strlen(buffer), 0, (struct sockaddr*)&clients[clientCount - 1].address, sizeof(clients[clientCount - 1].address));
}


  • Client Connection Handling: Inside an infinite loop, the server continuously receives messages from clients using recvfrom.
  • Client Information Printing: Information about the connected client is printed, and the client’s message is stored in the buffer.
  • Client Registration: The client’s socket, id, and address are stored in the client’s array.
  • Thread Creation: A new thread is created for each connected client using pthread_create, and the handleClient function is called.
  • Welcome Message: A welcome message is sent to the client for demonstration purposes.

Step 4: Handling Individual Clients in Threads

C




void *handleClient(void *arg) {
    int id = *((int *)arg);
    char buffer[MAX_MESSAGE_SIZE];
    ssize_t bytesRead;
 
    while (1) {
        // Receive message from client
        bytesRead = recvfrom(clients[id].socket, buffer, sizeof(buffer), 0, NULL, NULL);
        if (bytesRead == -1) {
            perror("Receive failed");
            exit(EXIT_FAILURE);
        }
 
        buffer[bytesRead] = '\0';
        printf("Client %d: %s", id + 1, buffer);
 
        // Broadcast the received message to all clients
        pthread_mutex_lock(&mutex);
        for (int i = 0; i < clientCount; ++i) {
            if (i != id) {
                sendto(clients[i].socket, buffer, bytesRead, 0, (struct sockaddr*)&clients[i].address, sizeof(clients[i].address));
            }
        }
        pthread_mutex_unlock(&mutex);
 
        // Send a message to the client (for demonstration purposes)
        sprintf(buffer, "Server: Message from server to Client %d\n", id + 1);
        sendto(clients[id].socket, buffer, strlen(buffer), 0, (struct sockaddr*)&clients[id].address, sizeof(clients[id].address));
    }
}


  • Thread Function Definition: The handleClient function is defined to handle communication for each connected client in a separate thread.
  • Message Reception: The thread continuously receives messages from its corresponding client using recvfrom.
  • Message Broadcast: The received message is broadcasted to all clients except the sender using a mutex for thread safety.
  • Server Message Sending: A message from the server to the client is sent for demonstration purposes.

Step 5: Cleanup and Program Termination

C




close(serverSocket);
pthread_mutex_destroy(&mutex);
 
return 0;


  • Socket Closure: The server socket is closed using close.
  • Mutex Destruction: The mutex is destroyed using pthread_mutex_destroy.
  • Program Termination: The program returns 0 to indicate successful termination.

Step 6: Write the Complete Code

Now, write the complete code on the server.c file.

C




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#define PORT 8888
#define MAX_MESSAGE_SIZE 1024
#define MAX_CLIENTS 10
 
typedef struct {
    struct sockaddr_in address;
    int socket;
    int id;
} Client;
 
Client clients[MAX_CLIENTS];
pthread_t threads[MAX_CLIENTS];
int clientCount = 0;
pthread_mutex_t mutex;
 
void *handleClient(void *arg) {
    int id = *((int *)arg);
    char buffer[MAX_MESSAGE_SIZE];
    ssize_t bytesRead;
 
    while (1) {
        // Receive message from client
        bytesRead = recvfrom(clients[id].socket, buffer, sizeof(buffer), 0, NULL, NULL);
        if (bytesRead == -1) {
            perror("Receive failed");
            exit(EXIT_FAILURE);
        }
 
        buffer[bytesRead] = '\0';
        printf("Client %d: %s", id + 1, buffer);
 
        // Broadcast the received message to all clients
        pthread_mutex_lock(&mutex);
        for (int i = 0; i < clientCount; ++i) {
            if (i != id) {
                sendto(clients[i].socket, buffer, bytesRead, 0, (struct sockaddr*)&clients[i].address, sizeof(clients[i].address));
            }
        }
        pthread_mutex_unlock(&mutex);
 
        // Send a message to the client (for demonstration purposes)
        sprintf(buffer, "Server: Message from server to Client %d\n", id + 1);
        sendto(clients[id].socket, buffer, strlen(buffer), 0, (struct sockaddr*)&clients[id].address, sizeof(clients[id].address));
    }
}
 
int main() {
    int serverSocket;
    struct sockaddr_in serverAddr;
    char buffer[MAX_MESSAGE_SIZE];
    socklen_t clientLen = sizeof(struct sockaddr_in);
    ssize_t bytesRead;
 
    // Create socket
    if ((serverSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }
 
    // Configure server address
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(PORT);
 
    // Bind socket
    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }
 
    // Initialize mutex
    pthread_mutex_init(&mutex, NULL);
 
    printf("Server listening on port %d...\n", PORT);
 
    // Create a thread for each client
    while (1) {
        // Receive message from client
        bytesRead = recvfrom(serverSocket, buffer, sizeof(buffer), 0, (struct sockaddr*)&clients[clientCount].address, &clientLen);
        if (bytesRead == -1) {
            perror("Receive failed");
            exit(EXIT_FAILURE);
        }
 
        buffer[bytesRead] = '\0';
        printf("Client %d connected: %s", clientCount + 1, buffer);
 
        // Add client to the list
        clients[clientCount].socket = serverSocket;
        clients[clientCount].id = clientCount;
        pthread_create(&threads[clientCount], NULL, handleClient, (void*)&clients[clientCount].id);
        clientCount++;
 
        // Send a welcome message to the client (for demonstration purposes)
        sprintf(buffer, "Server: Welcome, you are Client %d\n", clientCount);
        sendto(clients[clientCount - 1].socket, buffer, strlen(buffer), 0, (struct sockaddr*)&clients[clientCount - 1].address, sizeof(clients[clientCount - 1].address));
    }
 
    close(serverSocket);
    pthread_mutex_destroy(&mutex);
 
    return 0;
}


Server Script Code

How to create a multi-chat server using UDP?

In this article, we will see the development of a Multi-Threaded UDP Chat Server-Client Network for Data Transfer in Linux. UDP is used for low latency and connectionless characteristics, the architecture consists of a server managing multiple clients through threading. This networked chat application facilitates real-time communication, allowing users to exchange messages seamlessly. We will create the Server and Client script and perform live execution of communication between the server and multiple clients.

Similar Reads

Creating Server Script

In this section, we will create the server script in C language. So follow the steps and break down the script to understand the implementation of the server....

Creating Client Script

...

Step 2: Client Initialization and Receive Thread

...

Steps to Execute Scripts

...

Conclusion

...