1. Overview

In this article, we will identify what Unix Sockets are, how we can interact with them, and how we can connect to them in a practical use case example.

2. Introduction to Sockets

First, we need to establish a baseline understanding of what a socket is in the world of Linux. We’ll focus more on Unix Sockets here, but the underlying API for Network Sockets is very similar.

2.1. Sockets in Linux

A socket in Linux is a bidirectional communication pipe. Unlike standard FIFOs or pipes, work with sockets is done using the sockets interface as opposed to the file interface.

Let’s use two quick commands to learn more. The first command is nc, which is short for netcat. The netcat utility can be used for many tasks involving networking in Linux. For example, let’s use netcat to quickly create a Unix Socket:

$ nc -U /tmp/demo.sock -l

The -U parameter tells netcat to use a Unix Socket file, which we have specified. The -l parameter tells it to act as the server-side and listen on the specified socket for incoming connections.

Now, let’s use the lsof command to inspect the file created by netcat. The lsof command is a utility used to list and give information about files that are in use by processes. The -U option tells lsof to only list Unix Socket files, but this would list many sockets, and in our case, we want to focus on one in particular by specifying it directly as an argument:

$ lsof /tmp/demo.sock 
COMMAND     PID  USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
nc      3491531 admin    3u  unix 0x0000000000000000      0t0 25487430 /tmp/demo.sock type=STREAM

We have some good info on the process that is using /tmp/demo.sock here, including the command, PID, and user. We see a field called FD. When Linux processes need to perform I/O operations, they do so by reading or writing to file descriptors. Common examples are stdin, stdout, and stderr, which map to the file descriptors 0, 1, and 2, respectively.

2.2. Socket Types

Let’s go deeper into the last string in the output of our previous lsof command, type=STREAM. Both Network and Unix Sockets have several socket types. They share two main types, SOCK_STREAM and SOCK_DGRAM.

Network Sockets using SOCK_STREAM will use TCP, while those using SOCK_DGRAM will use UDP. Since UDP is unreliable by definition, any process that requires reliable data transfer over a network socket should use a network socket of type SOCK_STREAM. However, when it comes to Unix Sockets, both types are reliable.

The difference between the two types for Unix Sockets is that the SOCK_DGRAM type preserves message boundaries but is connectionless. In contrast, the SOCK_STREAM type does not preserve message boundaries but is connection-oriented.

Since Linux 2.6.4, there is another type of Unix Socket called SOCK_SEQPACKET that both preserves message boundaries and is connection-oriented.

2.3. SOCK_STREAM vs. SOCK_DGRAM Connection Behavior

Let’s demonstrate the difference between the two main types of Unix Sockets. We can do this with our handy netcat command:

$ nc -U /tmp/demo.sock -u -l

The command is the same as the previous netcat command but with the addition of a lowercase -u. This extra parameter tells netcat we want a Unix Socket of type SOCK_DGRAM. Let’s check it with lsof:

$ lsof /tmp/demo.sock
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF   NODE NAME
nc      55330 admin    3u  unix 0x0000000000000000      0t0 678755 /tmp/demo.sock type=DGRAM

Now, we have our SOCK_DGRAM Unix Socket. Let’s connect to it and see how it behaves. We can fire up a netcat client in another terminal:

$ nc -U /tmp/demo.sock -u

If we don’t add the -u parameter, we’ll get an error telling us that the protocol is the wrong type for the server socket.

We can provide input to the terminal, and when we press enter, we can see it on the other side. As sockets are bidirectional, both sides can send and receive.

Now, we’ll kill the server-side. The client stays up, and we can continue typing away and ‘sending’ data. We don’t have any indication that the server-side is down – that’s because a SOCK_DGRAM Unix Socket is connectionless.

Now, if we stop the client as well and remove the -u parameter to start the netcat server and client with a Unix Socket of type SOCK_STREAM, we can perform the same test, and we’ll see that when the server-side closes the connection, our client-side notices and it is also closed.

2.4. Unix Sockets Permissions

Unix Sockets use the permissions of the directory they’re in. Therefore, the process must have write and execute permissions on the directory to create the socket file. The same is true for any process that wishes to connect to the socket.

3. Practical Use Case Example: mysql.sock and SSH Forwarding

Using the popular MySQL database as an example, we can understand the advantage of using Unix Sockets when possible. When using a Unix Socket as opposed to a Network Socket with MySQL, there’s a measurable performance win from not having to incur the overhead for TCP/IP.

If we decide to use a Unix Socket, perhaps for the performance benefits, we would still like to have the ability to manage our services remotely. We can see we have a Unix Socket for MySQL:

$ lsof /var/run/mysqld/mysqld.sock
COMMAND     PID  USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
mysqld  3230830 mysql   32u  unix 0xffff8a6472b84000      0t0 24740620 /var/run/mysqld/mysqld.sock type=STREAM

On our admin laptop/desktop, we open up a terminal and run the following ssh command:

$ ssh -N -L 1234:/var/run/mysqld/mysqld.sock demo

The above command assumes we’re connecting to the same user – admin in this case – as the current session on our local system. It also assumes we have a .ssh/config file with the following entry where remote_host_ip is an IP address specific to the environment:

Host demo
   Hostname <remote_host_ip>

Now, we open our favorite database client. For the connection in our database client, based on the ssh tunnel we created earlier, we’ll provide the connection info:

  • Host: localhost
  • Port: 1234

Now, when our database management client connects to port 1234 on our localhost, the connection is forwarded through the ssh tunnel and connected to the MySQL database through the Unix Socket.

4. Conclusion

In this article, we took a brief tour of Unix Sockets in Linux and learned how to interact with them through common Linux utilities. We also worked through a practical example of Unix Socket usage by MySQL and how to work with it remotely. We hope this was an interesting read and that you are now able to work with Unix Sockets more comfortably.