Computer Networks Lab Programs

Socket programming exercises — UDP, TCP, concurrent servers

Q1. Socket Programming using UDP to Generate Prime Number Series

Algorithm

  1. Start.
  2. Server: create a UDP socket using socket(AF_INET, SOCK_DGRAM, 0).
  3. Server: initialize the server address structure with IP, port, and bind the socket using bind().
  4. Server: wait to receive a request from the client using recvfrom(), which also gives the client's address.
  5. Server: on receiving the request (the count N of primes needed), generate the first N primes by checking each candidate for divisibility from 2 up to its square root.
  6. Server: send the generated prime series back to the client using sendto(), addressed to the client's address from recvfrom().
  7. Server: close the socket.
  8. Client: create a UDP socket using socket(AF_INET, SOCK_DGRAM, 0).
  9. Client: initialize the server's address structure with the server's IP and port.
  10. Client: read N from the user and send it to the server using sendto().
  11. Client: wait to receive the prime series from the server using recvfrom().
  12. Client: display the received prime series.
  13. Client: close the socket.
  14. Stop.

Server — udp_prime_server.c

udp_prime_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 5000
#define BUF_SIZE 4096

int isPrime(int n) {
    if (n < 2) return 0;
    for (int i = 2; i * i <= n; i++)
        if (n % i == 0) return 0;
    return 1;
}

int main() {
    int sockfd;
    char sendBuff[BUF_SIZE], recvBuff[BUF_SIZE];
    struct sockaddr_in servAddr, cliAddr;
    socklen_t cliLen = sizeof(cliAddr);

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) { perror("socket"); exit(1); }

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = INADDR_ANY;
    servAddr.sin_port = htons(PORT);

    if (bind(sockfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
        perror("bind"); exit(1);
    }

    printf("UDP Prime Server listening on port %d...\n", PORT);

    while (1) {
        memset(recvBuff, 0, BUF_SIZE);
        cliLen = sizeof(cliAddr);
        int n = recvfrom(sockfd, recvBuff, BUF_SIZE, 0,
                          (struct sockaddr *)&cliAddr, &cliLen);
        if (n < 0) continue;

        int count = atoi(recvBuff);
        printf("Request received for %d prime numbers\n", count);
        if (count > 250) count = 250;

        memset(sendBuff, 0, BUF_SIZE);
        int num = 2, found = 0;
        while (found < count) {
            if (isPrime(num)) {
                char temp[16];
                sprintf(temp, "%d ", num);
                strcat(sendBuff, temp);
                found++;
            }
            num++;
        }

        sendto(sockfd, sendBuff, strlen(sendBuff), 0,
               (struct sockaddr *)&cliAddr, cliLen);
    }

    close(sockfd);
    return 0;
}

Client — udp_prime_client.c

udp_prime_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 5000
#define BUF_SIZE 4096
#define SERVER_IP "127.0.0.1"

int main() {
    int sockfd;
    char sendBuff[BUF_SIZE], recvBuff[BUF_SIZE];
    struct sockaddr_in servAddr;
    socklen_t servLen = sizeof(servAddr);
    int n;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) { perror("socket"); exit(1); }

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(PORT);
    inet_pton(AF_INET, SERVER_IP, &servAddr.sin_addr);

    printf("Enter number of prime numbers required: ");
    scanf("%d", &n);

    memset(sendBuff, 0, BUF_SIZE);
    sprintf(sendBuff, "%d", n);
    sendto(sockfd, sendBuff, strlen(sendBuff), 0,
           (struct sockaddr *)&servAddr, servLen);

    memset(recvBuff, 0, BUF_SIZE);
    recvfrom(sockfd, recvBuff, BUF_SIZE, 0,
             (struct sockaddr *)&servAddr, &servLen);

    printf("Prime number series: %s\n", recvBuff);

    close(sockfd);
    return 0;
}
How to run
Terminal 1 (server): gcc udp_prime_server.c -o server && ./server
Terminal 2 (client): gcc udp_prime_client.c -o client && ./client
Enter number of prime numbers required: 10 Prime number series: 2 3 5 7 11 13 17 19 23 29

Q2. Socket Programming using TCP to Generate Fibonacci Series

Algorithm

  1. Start.
  2. Server: create a TCP socket using socket(AF_INET, SOCK_STREAM, 0).
  3. Server: initialize the server address structure with IP, port, and bind the socket using bind().
  4. Server: put the socket in listening mode using listen(), specifying the max pending-connections queue length.
  5. Server: accept an incoming client connection using accept(), which returns a new socket descriptor for communication.
  6. Server: receive the request from the client (count N of Fibonacci terms needed) using recv()/read().
  7. Server: generate the first N terms using F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2).
  8. Server: send the generated series back using send()/write().
  9. Server: close the connection socket and the listening socket.
  10. Client: create a TCP socket using socket(AF_INET, SOCK_STREAM, 0).
  11. Client: initialize the server's address structure with the server's IP and port.
  12. Client: connect to the server using connect().
  13. Client: read N from the user and send it using send()/write().
  14. Client: receive the Fibonacci series using recv()/read().
  15. Client: display the received series.
  16. Client: close the socket.
  17. Stop.

Server — tcp_fibonacci_server.c

tcp_fibonacci_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 6000
#define BUF_SIZE 4096

int main() {
    int listenfd, connfd;
    char sendBuff[BUF_SIZE], recvBuff[BUF_SIZE];
    struct sockaddr_in servAddr, cliAddr;
    socklen_t cliLen;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0) { perror("socket"); exit(1); }

    int opt = 1;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = INADDR_ANY;
    servAddr.sin_port = htons(PORT);

    if (bind(listenfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
        perror("bind"); exit(1);
    }
    if (listen(listenfd, 5) < 0) { perror("listen"); exit(1); }

    printf("TCP Fibonacci Server listening on port %d...\n", PORT);

    while (1) {
        cliLen = sizeof(cliAddr);
        connfd = accept(listenfd, (struct sockaddr *)&cliAddr, &cliLen);
        if (connfd < 0) { perror("accept"); continue; }

        memset(recvBuff, 0, BUF_SIZE);
        read(connfd, recvBuff, BUF_SIZE - 1);
        int count = atoi(recvBuff);
        printf("Request received for %d Fibonacci terms\n", count);
        if (count > 80) count = 80; // cap to prevent numeric & buffer overflow

        memset(sendBuff, 0, BUF_SIZE);
        long a = 0, b = 1, c;
        char temp[32];
        for (int i = 0; i < count; i++) {
            sprintf(temp, "%ld ", a);
            strcat(sendBuff, temp);
            c = a + b;
            a = b;
            b = c;
        }

        write(connfd, sendBuff, strlen(sendBuff));
        close(connfd);
    }

    close(listenfd);
    return 0;
}

Client — tcp_fibonacci_client.c

tcp_fibonacci_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 6000
#define BUF_SIZE 4096
#define SERVER_IP "127.0.0.1"

int main() {
    int sockfd;
    char sendBuff[BUF_SIZE], recvBuff[BUF_SIZE];
    struct sockaddr_in servAddr;
    int n;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) { perror("socket"); exit(1); }

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(PORT);
    inet_pton(AF_INET, SERVER_IP, &servAddr.sin_addr);

    if (connect(sockfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
        perror("connect"); exit(1);
    }

    printf("Enter number of Fibonacci terms required: ");
    scanf("%d", &n);

    memset(sendBuff, 0, BUF_SIZE);
    sprintf(sendBuff, "%d", n);
    write(sockfd, sendBuff, strlen(sendBuff));

    memset(recvBuff, 0, BUF_SIZE);
    read(sockfd, recvBuff, BUF_SIZE);

    printf("Fibonacci series: %s\n", recvBuff);

    close(sockfd);
    return 0;
}
How to run
Terminal 1 (server): gcc tcp_fibonacci_server.c -o server && ./server
Terminal 2 (client): gcc tcp_fibonacci_client.c -o client && ./client
Enter number of Fibonacci terms required: 8 Fibonacci series: 0 1 1 2 3 5 8 13

Q3. Multi-User Chat Server Using TCP

Aim

To implement a multi-user chat server using TCP as the transport layer protocol, where messages typed by any connected client are broadcast to every other connected client in real time.

Algorithm

  1. Server: create a TCP socket, bind() it to a fixed port, and listen() for incoming connections. Maintain an array to hold the socket descriptor of every connected client.
  2. Server: in a loop, use select() to simultaneously monitor the listening socket and every connected client socket for activity, without blocking on any single one.
  3. Server: if the listening socket is ready, accept() the new connection and store its descriptor in the client array.
  4. Server: if a client socket is ready, read() the message sent by that client.
  5. Server: if read() returns 0, the client has disconnected — close() its socket and remove it from the array.
  6. Server: otherwise, broadcast the received message to every other connected client using send(), skipping the sender.
  7. Client: connect() to the server, then loop using select() to simultaneously monitor standard input (keyboard) and the socket.
  8. Client: when the user types a line, send() it to the server; when data arrives on the socket, read() and print() it.
  9. Repeat until the connection is closed (Ctrl+C or the server shutting down).

Server — chat_server.c

chat_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>

#define PORT 5555
#define MAX_CLIENTS 30
#define BUF 1024

int main() {
    int server_fd, new_socket, client_socket[MAX_CLIENTS] = {0};
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    fd_set readfds;
    char buffer[BUF];

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    bind(server_fd, (struct sockaddr *)&address, sizeof(address));
    listen(server_fd, MAX_CLIENTS);

    printf("Chat server listening on port %d...\n", PORT);

    while (1) {
        FD_ZERO(&readfds);
        FD_SET(server_fd, &readfds);
        int max_sd = server_fd;

        for (int i = 0; i < MAX_CLIENTS; i++) {
            int sd = client_socket[i];
            if (sd > 0) FD_SET(sd, &readfds);
            if (sd > max_sd) max_sd = sd;
        }

        select(max_sd + 1, &readfds, NULL, NULL, NULL);

        /* New connection */
        if (FD_ISSET(server_fd, &readfds)) {
            new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
            printf("New client connected, socket fd: %d\n", new_socket);
            for (int i = 0; i < MAX_CLIENTS; i++) {
                if (client_socket[i] == 0) {
                    client_socket[i] = new_socket;
                    break;
                }
            }
        }

        /* Data from an existing client */
        for (int i = 0; i < MAX_CLIENTS; i++) {
            int sd = client_socket[i];
            if (sd > 0 && FD_ISSET(sd, &readfds)) {
                int valread = read(sd, buffer, BUF - 1);
                if (valread <= 0) {
                    close(sd);
                    client_socket[i] = 0;
                } else {
                    buffer[valread] = '\0';
                    printf("Broadcasting: %s", buffer);
                    for (int j = 0; j < MAX_CLIENTS; j++) {
                        if (client_socket[j] != 0 && client_socket[j] != sd)
                            send(client_socket[j], buffer, valread, 0);
                    }
                }
            }
        }
    }

    return 0;
}

Client — chat_client.c

chat_client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>

#define PORT 5555
#define BUF 1024

int main() {
    int sock;
    struct sockaddr_in serv_addr;
    char buffer[BUF];
    fd_set readfds;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

    connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    printf("Connected to chat server. Type messages (Ctrl+C to quit).\n");

    while (1) {
        FD_ZERO(&readfds);
        FD_SET(0, &readfds); /* stdin */
        FD_SET(sock, &readfds);
        int max_sd = sock;

        select(max_sd + 1, &readfds, NULL, NULL, NULL);

        if (FD_ISSET(0, &readfds)) {
            fgets(buffer, BUF, stdin);
            send(sock, buffer, strlen(buffer), 0);
        }

        if (FD_ISSET(sock, &readfds)) {
            int n = read(sock, buffer, BUF - 1);
            if (n <= 0) {
                printf("Server closed the connection.\n");
                break;
            }
            buffer[n] = '\0';
            printf("Other user: %s", buffer);
        }
    }

    close(sock);
    return 0;
}
How to run
Terminal 1 (server): gcc chat_server.c -o server && ./server
Terminal 2 (client A): gcc chat_client.c -o client && ./client
Terminal 3 (client B): ./client
Run one server and two or more client instances; a message typed in any client appears in every other connected client's terminal.
Connected to chat server. Type messages (Ctrl+C to quit). sup my man Other user: yo im here too Other user: bro is chromed out fr

Q4. Concurrent Time Server Using UDP

Aim

To implement a concurrent Time Server application using UDP, running at a remote/local server, where the client sends a time request and the server replies with its current system time, which the client then displays.

Algorithm

  1. Server: create a UDP socket with socket(AF_INET, SOCK_DGRAM, 0) and bind() it to a fixed port.
  2. Server: call signal(SIGCHLD, SIG_IGN) so that terminated child processes are reaped automatically (no zombies).
  3. Server: loop — call recvfrom() to block and wait for a time-request datagram from any client.
  4. Server: on receiving a request, call fork(). In the child process, fetch the current time with time()/ctime() and send it back to the client's address using sendto(), then exit().
  5. Server: the parent process immediately loops back to recvfrom() to accept the next request, so multiple requests are served concurrently without one blocking another.
  6. Client: create a UDP socket and sendto() a request datagram to the server's IP address and port.
  7. Client: call recvfrom() to receive the time string reply and display it on screen.

Server — udp_time_server.c

udp_time_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>

#define PORT 6060
#define BUF 256

int main() {
    int sockfd;
    struct sockaddr_in servaddr, cliaddr;
    char buffer[BUF];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);

    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    printf("Concurrent UDP time server listening on port %d...\n", PORT);
    fflush(stdout);

    signal(SIGCHLD, SIG_IGN); /* auto-reap finished children */

    while (1) {
        socklen_t len = sizeof(cliaddr);
        int n = recvfrom(sockfd, buffer, BUF - 1, 0, (struct sockaddr *)&cliaddr, &len);
        buffer[n] = '\0';

        printf("Time request received from %s:%d\n",
               inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
        fflush(stdout);

        pid_t pid = fork();
        if (pid == 0) {
            /* child sends the reply, parent immediately serves the next request */
            time_t now = time(NULL);
            char *timestr = ctime(&now);
            sendto(sockfd, timestr, strlen(timestr), 0, (struct sockaddr *)&cliaddr, len);
            exit(0);
        }
    }

    return 0;
}

Client — udp_time_client.c

udp_time_client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 6060
#define BUF 256

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char msg[] = "TIME_REQUEST";
    char buffer[BUF];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

    sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));

    socklen_t len = sizeof(servaddr);
    int n = recvfrom(sockfd, buffer, BUF - 1, 0, (struct sockaddr *)&servaddr, &len);
    buffer[n] = '\0';

    printf("Server system time: %s", buffer);

    close(sockfd);
    return 0;
}
How to run
Terminal 1 (server): gcc udp_time_server.c -o server && ./server
Terminal 2 (client): gcc udp_time_client.c -o client && ./client
Server system time: Mon Sep 14 21:58:42 2026

Q5. Concurrent FTP Using TCP

Aim

To develop a concurrent file server that provides the file requested by a client if it exists; if not, the server sends an appropriate error message. The server also sends its process ID (PID) to the client, to be displayed alongside the file contents or the error message.

Algorithm

  1. Server: create a TCP socket, bind() it to a fixed port, and listen() for connections.
  2. Server: call signal(SIGCHLD, SIG_IGN) so terminated child processes are reaped automatically.
  3. Server: loop — call accept() to block until a client connects.
  4. Server: on accepting, call fork(). The child closes its copy of the listening socket and handles this client; the parent closes its copy of the connected socket and immediately loops back to accept() the next client — this is what makes the server concurrent.
  5. Child: read() the filename sent by the client, then send() its own process ID (getpid()) back to the client first.
  6. Child: attempt to fopen() the requested file. If it exists, read it in chunks with fread() and send() each chunk to the client; if fopen() fails, send() a "file not found" error message instead.
  7. Child: close() the connection and exit().
  8. Client: connect() to the server, send() the desired filename, then repeatedly read() and print everything the server sends back (the PID line followed by the file contents or the error message).

Server — file_server.c

file_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <arpa/inet.h>

#define PORT 7070
#define BUF 1024

int main() {
    int server_fd, new_socket, opt = 1;
    struct sockaddr_in address;
    socklen_t addrlen = sizeof(address);
    char buffer[BUF];

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    bind(server_fd, (struct sockaddr *)&address, sizeof(address));
    listen(server_fd, 5);

    printf("Concurrent file server listening on port %d...\n", PORT);
    fflush(stdout);

    signal(SIGCHLD, SIG_IGN);

    while (1) {
        new_socket = accept(server_fd, (struct sockaddr *)&address, &addrlen);

        if (fork() == 0) {
            close(server_fd); /* child does not need the listening socket */

            int n = read(new_socket, buffer, BUF - 1);
            buffer[n] = '\0';
            buffer[strcspn(buffer, "\n")] = '\0';

            printf("[PID %d] File requested: %s\n", getpid(), buffer);
            fflush(stdout);

            char pidmsg[64];
            snprintf(pidmsg, sizeof(pidmsg), "SERVER_PID:%d\n", getpid());
            send(new_socket, pidmsg, strlen(pidmsg), 0);

            FILE *fp = fopen(buffer, "r");
            if (fp == NULL) {
                char *notfound = "ERROR: File not found on server.\n";
                send(new_socket, notfound, strlen(notfound), 0);
            } else {
                char filebuf[BUF];
                size_t bytes;
                while ((bytes = fread(filebuf, 1, BUF, fp)) > 0)
                    send(new_socket, filebuf, bytes, 0);
                fclose(fp);
            }

            close(new_socket);
            exit(0);
        }

        close(new_socket); /* parent does not need the connected socket */
    }

    return 0;
}

Client — file_client.c

file_client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 7070
#define BUF 1024

int main() {
    int sock;
    struct sockaddr_in serv_addr;
    char filename[128], buffer[BUF];

    sock = socket(AF_INET, SOCK_STREAM, 0);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

    connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    printf("Enter filename to request: ");
    fgets(filename, sizeof(filename), stdin);
    send(sock, filename, strlen(filename), 0);

    int n;
    while ((n = read(sock, buffer, BUF - 1)) > 0) {
        buffer[n] = '\0';
        printf("%s", buffer);
    }

    close(sock);
    return 0;
}
How to run
Create a .txt file (e.g. hello.txt) in the same directory as the server.
Terminal 1 (server): gcc file_server.c -o server && ./server
Terminal 2 (client): gcc file_client.c -o client && ./client
Enter filename to request: hello.txt SERVER_PID:16321 im writing bs here