Trusted answers to developer questions
Trusted Answers to Developer Questions

Related Tags

unix

What are Unix Domain Sockets?

Amaaz Ahmad

A socket can be said to be a gateway for communication between processes. It allows two processes to send and receive messages.

There are two primary types of sockets in Unix:

  • Internet Domain Sockets
  • Unix Domain Sockets

The Internet Domain Sockets allow processes to communicate over a network, whereas the Unix Domain Sockets enable communication between running processes on the same machine.

We will focus on the Unix domain sockets for now.

Stages of Communication via a Socket

We will focus on the sockets with the following properties:

  • domain: AF_UNIX
  • type: SOCK_STREAM

These properties allow us to send and receive streams of data over local communication channels. You can find more information regarding the properties and other available options here.

When processes are communicating, one of the processes acts as a server, and the other acts as a client. The stages of a socket in both are defined below.

Socket in a server

  1. First, we create a new socket using the socket() system call. The file descriptor returned by this system call is used to refer to the socket later on.
  2. The Unix domain sockets communicate through a file. We use the bind() system call to bind the newly created socket to that file.
  3. Then, we use the listen() system call to tell the system that this socket will now be open to new connections.
  4. The accept() system call is used to accept an incoming connection.

After the above steps, the read() and write() functions are used along with the file descriptor returned by the accept() function to transmit and receive messages.

Once the communication is done, we use the unlink() function to unlink the file from the socket used in the bind() function. Then we use the close() system call to close the socket.

Socket in a client

  1. We first create a new socket using the socket() system call. The file descriptor returned by this system call is used later on to refer to the socket.
  2. We use the connect() function to connect to the socket created by the server. In the case of Unix domain sockets, we use the file’s name to specify the correct socket. The connect() function call must be made after the listen() function is called on the server.

After the above steps, the read() and write() functions are used with the file descriptor returned by the socket() function call to transmit and receive messages.

Once the communication is complete, we use the close() function to close the socket.

The following figure illustrates the communication process. The grey read() and write() function calls use the file descriptor returned by the accept() function.

Communication process in Unix Domain Sockets

Examples

Following are the sample codes for the server and the client:

The code is written in C language

server.c
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>

#define NAME "/tmp/sock"


main()
{
    int sock, msgsock, rval;
    struct sockaddr_un server;

    // creating a buffer to read data
    char buf[1024];

    // creating a new socket
    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("opening stream socket");
        exit(1);
    }
    server.sun_family = AF_UNIX;
    strcpy(server.sun_path, NAME);

    // binding the socket to the file
    if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
        perror("binding stream socket");
        exit(1);
    }
    printf("Socket has name %s\n", server.sun_path);
    listen(sock, 5);
    
    // waiting for the client to connect after listen() function call
    printf("WAITING FOR THE CLIENT\n");
    msgsock = accept(sock, 0, 0);
    printf("server: accept()\n");
    if (msgsock == -1)
        perror("accept");
    else{

        char msg1[]="Sleep";
        if (write(msgsock, msg1, sizeof(msg1)) < 0)
            perror("writing on stream socket");
        printf("The server requests the client to sleep\n");

        while(1){
            bzero(buf, sizeof(buf));
            if ((rval = read(msgsock, buf, 1024)) < 0)
                perror("reading stream message");
            else if(rval==0)
                continue;
            else{
                if(strcmp("Done", buf)==0){
                    printf("Message from the client : %s\n",buf);
                    break;
                }
                continue;
            }
        }

        char msg2[]="Quit";
        if (write(msgsock, msg2, sizeof(msg2)) < 0)
            perror("writing on stream socket");
        printf("The server requests the client to quit\n");
    }

    close(msgsock);

    unlink(NAME);
    close(sock);
}

In the above example, the server first waits for the client to connect. Once the connection is established, the server sends a message to the client. The client receives the message and checks if the message is “Sleep.” If it is, the client goes to sleep for 5 seconds. Then the client sends a message to the server. The server checks this message if it is “Done”. If it is, the server sends a “Quit” message to the client and the client shuts down.

RELATED TAGS

unix

CONTRIBUTOR

Amaaz Ahmad
Copyright ©2022 Educative, Inc. All rights reserved
RELATED COURSES

View all Courses

Keep Exploring