Open In App

Creating Unix Sockets

Sockets are a means to allow communication between two different processes over the same or different machines/networks. To be more precise, it's a way to talk to other computers and exchange data. In Unix, every I/O action is done by writing or reading a file descriptor. Sockets are the end point of communication with each process having its socket and a socket descriptor for all the operations. In this article, we are going to read more about creating a socket in a Unix system and implementing both client and server-side programs.

Creating Server Script

The system calls for establishing a connection is different for both the client and the server, but both involve the basic construct of a socket. Both processes establish their sockets. 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 vim editor by using the command in the terminal.

vi server.c
Creating server.c file

Creating server.c file

Step 2: Server Initialization and Socket Binding

int server_fd, new_socket;
ssize_t valread;
struct sockaddr_in address;
int opt = 1;
socklen_t addrlen = sizeof(address);
char buffer[1024] = { 0 };

// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}

// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET,
               SO_REUSEADDR | SO_REUSEPORT, &opt,
               sizeof(opt))) {
    perror("setsockopt");
    exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr*)&address,
         sizeof(address))
    < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);

Step 3: Listening Multiple Clients

int server_fd, new_socket;
ssize_t valread;
struct sockaddr_in address;
int opt = 1;
socklen_t addrlen = sizeof(address);
char buffer[1024] = { 0 };

// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}

// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET,
               SO_REUSEADDR | SO_REUSEPORT, &opt,
               sizeof(opt))) {
    perror("setsockopt");
    exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr*)&address,
         sizeof(address))
    < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);

// Listening multiple clients
if (listen(server_fd, 3) < 0) {
    perror("listen");
    exit(EXIT_FAILURE);
}

Step 4: Handling Individual Clients using the accept function

if ((new_socket = accept(
         server_fd, (struct sockaddr*)&address, &addrlen))
    < 0) {
    perror("accept");
    exit(EXIT_FAILURE);
}
valread = read(new_socket, buffer,
               1024 - 1); // subtract 1 for the null
                          // terminator at the end
printf("%s\n", buffer);
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");

Step 5: Transferring and Data Cleanup

// closing the connected socket
close(new_socket);
// closing the listening socket
close(server_fd);
return 0;

Step 6: Write the Complete Code

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

// Server side C program to demonstrate Unix Socket

#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
int main(int argc, char const* argv[])
{
    int server_fd, new_socket;
    ssize_t valread;
    struct sockaddr_in address;
    int opt = 1;
    socklen_t addrlen = sizeof(address);
    char buffer[1024] = { 0 };
    char* hello = "Hello from server";

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // Forcefully attaching socket to the port 8080
    if (setsockopt(server_fd, SOL_SOCKET,
                   SO_REUSEADDR | SO_REUSEPORT, &opt,
                   sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // Forcefully attaching socket to the port 8080
    if (bind(server_fd, (struct sockaddr*)&address,
             sizeof(address))
        < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    printf("Server listening on port %d...\n", PORT);
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((new_socket
         = accept(server_fd, (struct sockaddr*)&address,
                  &addrlen))
        < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    valread = read(new_socket, buffer,
                   1024 - 1); // subtract 1 for the null
                              // terminator at the end
    printf("%s\n", buffer);
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");

    // closing the connected socket
    close(new_socket);
    // closing the listening socket
    close(server_fd);
    return 0;
}
Server Script Code

Server Script Code

Creating Client Script

In this section, we will create the Client script through which multiple clients can connect to the server for data transfer and message transfer.

Step 1: Create a client.c File

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

vi client.c
Creating client.c file

Creating client.c file

Step 2: Client Initialization

int status, valread, client_fd;
struct sockaddr_in serv_addr;
char* hello = "Hello from client";
char buffer[1024] = { 0 };
if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    printf("\n Socket creation error \n");
    return -1;
}

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);

// Convert IPv4 and IPv6 addresses from text to binary
// form
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)
    <= 0) {
    printf("\nInvalid address/ Address not supported \n");
    return -1;
}

Step 3: Message Sending and Cleanup

if ((status
     = connect(client_fd, (struct sockaddr*)&serv_addr,
               sizeof(serv_addr)))
    < 0) {
    printf("\nConnection Failed \n");
    return -1;
}
send(client_fd, hello, strlen(hello), 0);
printf("Hello message sent\n");
valread = read(client_fd, buffer,
               1024 - 1); // subtract 1 for the null
                          // terminator at the end
printf("%s\n", buffer);

// closing the connected socket
close(client_fd);
return 0;

Step 4: Write the Complete Code

Now, write the complete code for the client.c file.

// Client side socket
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080

int main(int argc, char const* argv[])
{
    int status, valread, client_fd;
    struct sockaddr_in serv_addr;
    char* hello = "Hello from client";
    char buffer[1024] = { 0 };
    if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // Convert IPv4 and IPv6 addresses from text to binary
    // form
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)
        <= 0) {
        printf(
            "\nInvalid address/ Address not supported \n");
        return -1;
    }

    if ((status
         = connect(client_fd, (struct sockaddr*)&serv_addr,
                   sizeof(serv_addr)))
        < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }
    send(client_fd, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    valread = read(client_fd, buffer,
                   1024 - 1); // subtract 1 for the null
                              // terminator at the end
    printf("%s\n", buffer);

    // closing the connected socket
    close(client_fd);
    return 0;
}
Client Script Code

Client Script Code

Steps to Execute Scripts

Step 1: Compile Server and Client Scripts

Once we have created the scripts, we need to compile them with the gcc compiler. So execute the below commands in the terminal to compile it successfully:

gcc server.c -o server 
gcc client.c -o client

Step 2: Checking Socket Communication

In the below output, we can see that we have executed server and multiple client scripts.

Server Listening for Communication

Server Listening for Communication


Client Sends Message

Client Sends Message

Conclusion

In conclusion, Sockets are one of the best ways to make strong and effective communication. IPC (inter-process communication) inside the same host has made strong Unix socket programming in C. It helps to build reliable and high-performance communication channels for processes operating on the same computer by using Unix domain sockets. The client initiates a TCP socket, configures the server address, and connects for message reception.

Article Tags :