What is a Unix Domain Socket (UDS) #
Unix Domain Socket (UDS) is an inter-process communication (IPC) mechanism in Linux/Unix systems. Unlike traditional TCP/IP sockets, UDS is used exclusively for communication between processes on the same host, bypassing the network protocol stack, which results in higher efficiency and lower latency. It communicates through a special file in the filesystem (typically a socket file), providing reliable bidirectional data transmission.
UDS supports two communication modes:
- Stream (SOCK_STREAM): Similar to TCP, it provides connection-oriented, reliable data stream transmission.
 - Datagram (SOCK_DGRAM): Similar to UDP, it provides connectionless, unreliable datagram transmission.
 
Advantages of UDS #
- High Performance: By avoiding the network protocol stack, UDS offers higher communication efficiency than TCP/IP sockets, especially for high-frequency, small-data scenarios.
 - Security: UDS leverages filesystem permissions, allowing access control through Linux file permissions, enhancing security.
 - Simplicity: No need to configure IP addresses or ports; only a file path is required.
 - Versatility: In addition to regular data, UDS supports transferring file descriptors, credentials, and more.
 
Use Cases for UDS #
UDS is widely used in Linux systems for inter-process communication, such as:
- Local Service Communication: For example, communication between database clients and servers (e.g., MySQL).
 - System Services: Services like D-Bus and X11 use UDS for efficient communication.
 - Microservices Architecture: Communication between microservices on the same host to reduce network overhead.
 
Simple Example: Using UDS for Communication #
Below is a simple C language example demonstrating how to use UDS for communication between a client and a server. The server listens for client messages and responds with a confirmation.
Server Code #
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCKET_PATH "/tmp/my_uds_socket"
#define BUFFER_SIZE 256
int main() {
    int server_fd, client_fd;
    struct sockaddr_un server_addr, client_addr;
    char buffer[BUFFER_SIZE];
    socklen_t client_len = sizeof(client_addr);
    // Create UDS socket
    server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("Socket creation failed");
        exit(1);
    }
    // Set server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);
    // Bind socket
    unlink(SOCKET_PATH); // Remove old socket file
    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("Bind failed");
        exit(1);
    }
    // Listen for connections
    if (listen(server_fd, 5) == -1) {
        perror("Listen failed");
        exit(1);
    }
    printf("Server listening on %s\n", SOCKET_PATH);
    // Accept client connection
    client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
    if (client_fd == -1) {
        perror("Accept failed");
        exit(1);
    }
    // Receive and respond to messages
    while (1) {
        int len = recv(client_fd, buffer, BUFFER_SIZE, 0);
        if (len <= 0) break;
        buffer[len] = '\0';
        printf("Received: %s\n", buffer);
        const char *response = "Message received!";
        send(client_fd, response, strlen(response), 0);
    }
    // Cleanup
    close(client_fd);
    close(server_fd);
    unlink(SOCKET_PATH);
    return 0;
}
Client Code #
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCKET_PATH "/tmp/my_uds_socket"
#define BUFFER_SIZE 256
int main() {
    int client_fd;
    struct sockaddr_un server_addr;
    char buffer[BUFFER_SIZE];
    // Create UDS socket
    client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_fd == -1) {
        perror("Socket creation failed");
        exit(1);
    }
    // Set server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);
    // Connect to server
    if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("Connect failed");
        exit(1);
    }
    // Send message
    const char *message = "Hello, UDS Server!";
    send(client_fd, message, strlen(message), 0);
    // Receive server response
    int len = recv(client_fd, buffer, BUFFER_SIZE, 0);
    buffer[len] = '\0';
    printf("Server response: %s\n", buffer);
    // Cleanup
    close(client_fd);
    return 0;
}
How to Run #
- Compile the server and client code:
gcc server.c -o server gcc client.c -o client - Run the server:
./server - In another terminal, run the client:
./client 
Upon running, the server will receive the “Hello, UDS Server!” message from the client and respond with “Message received!”.
Notes #
- File Path: Ensure the 
SOCKET_PATHhas appropriate permissions and is not occupied by other processes. - Cleanup: The server should remove old socket files (using 
unlink) before starting to avoid binding failures. - Error Handling: In production, implement robust error handling to manage connection interruptions or data anomalies.
 
Conclusion #
Unix Domain Sockets are an efficient and reliable tool for inter-process communication in Linux systems, particularly suited for low-latency, high-security local communication scenarios. With simple file path configuration and robust filesystem permission support, UDS plays a critical role in system development. I hope this blog helps you better understand and utilize UDS!