Unix socket programming in C

A socket is an endpoint that allows bi-directional communication between two processes. With the help of sockets, processes can exchange information across a network. In the Unix system, we can create Unix sockets with the help of the C library sys/socket.h.

Unix sockets are essentially used for inter-process communication for processes on the same host rather than a network. This means that the two processes must be running on the same local machine to use Unix sockets to exchange data with each other.

Steps for using a Unix socket

Now that we have understood the purpose of a Unix socket, let's look at the steps to create a Unix socket and use it to perform inter-process communication in C applications with the help of a flow diagram.

Unix socket flow diagram
Unix socket flow diagram

To understand the steps illustrated in the diagram, we will break the diagram into two categories, server and client, and explain them individually.

Server Configurations


Create a socket
server_socket = socket(AF_UNIX, SOCK_STREAM, 0);

First, we will need to create a server-side socket which will be used to handle connections from the client. To create a socket, we will call the function socket() that takes the type of socket to be created as an argument. Since we are using Unix sockets, we will use the socket family of AF_UNIX, we will also use the standard socket type of SOCK_STREAM . The function, upon execution will return a file descriptor to the new socket.

Bind the socket
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "unix_socket");
int slen = sizeof(server_addr);
bind(server_socket, (struct sockaddr *) &server_addr, slen);

To bind a socket to a local address on the machine we use the bind() function. In the function we pass the file descriptor of the socket returned by the socket() function and the bind details that we specific in a structure of type sockaddr_un named server_addr in our application.

Listen for connection
listen(server_socket, 5);

Now we use the listen() function to listen for incoming connections. In the function, we pass the socket we want to listen to. We also pass the max number of connections to queue in the socket as the 2nd argument. In our code, we specified 5 max connection queues.

Accept client connection
int clen = sizeof(client_addr);
client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &clen);

To accept an incoming connection from the client, we can use the accept() function. The function will take the server socket as an argument and retrieve the first socket connection in the queue, create a new socket through which we can communicate with the client, and return the file descriptor for that socket.

Read from the client
read(client_socket, &ch, 1);

After a connection is established, we can then read data from the client socket using the read() system call by passing the client socket file descriptor.

Write to the client
write(client_socket, &ch, 1);

The server can also write data to the client by using the write() system call and passing the client socket's file descriptor.

Close the connection
close(client_socket);

Once the server is done sending and receiving data from the client, it can close the socket connection using the close() function and passing the socket's file descriptor client_socket in the function's argument.

Client configurations


Create a socket
server_socket = socket(AF_UNIX, SOCK_STREAM, 0);

The client also creates a similar socket as seen in the server configuration using the socket() function with the socket family of AF_UNIX and the socket type of SOCK_STREAM.

Note: The type of socket for the server and the the client should be the same for the client to establish a connection with the server.

Connect to server socket
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "unix_socket");
connection_result = connect(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));

Once a client has set up a socket, it will use the connect() method to try to establish a connection to the server socket. It requires the file descriptor for the server socket and the server address we wish to connect to as function arguments.


The function will return the value 0 upon a successful connection to the server; otherwise, it returns -1 which can be used for error handling.

Write to server
write(server_socket, &ch, 1);

If the client wants to send data to the server, it can use the write() system call by passing the file descriptor for the client socket.

Read from the server
read(server_socket, &ch, 1);

To read data from the server, the client can use the read() system call and pass the file descriptor for the client socket.

Close the connection
close(server_socket);
Closing the socket connection

Once the client is done sending and receiving data from the server, it can close the socket connection using the close() function and passing the socket's file descriptor server_socket in the function's argument.

Socket application

Below, we can see a C application that encloses all the steps that we have gone through above illustrating the process of how Unix sockets and created and user for inter-process communication.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

int main() {
    int server_socket;
    struct sockaddr_un server_addr;
    int connection_result;

    char ch='C';

    server_socket = socket(AF_UNIX, SOCK_STREAM, 0);

    server_addr.sun_family = AF_UNIX;
    strcpy(server_addr.sun_path, "unix_socket");

    connection_result = connect(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));

    if (connection_result == -1) {
        perror("Error:");
        exit(1);
    }

    write(server_socket, &ch, 1);
    read(server_socket, &ch, 1);
    printf("Client: I recieved %c from server!\n", ch);
    close(server_socket);
    exit(0);
}
Basic socket C application

When we click the run button, the client passes the letter C to the server. The server then increments the ASCII value of the letter sent by the client and sends the incremented character back to the client.

Note: We can change the letter sent to the server by modifying the char variable ch in line 15 of the file client.c and re-running the application.

Conclusion

IPC (inter-process communication) inside the same host is made strong and effective by Unix socket programming in C. Developers may build reliable and high-performance communication channels for processes operating on the same computer by using Unix domain sockets.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved