logo

Linux / Unix - Sockets

Unix Domain Sockets vs Internet Domain Sockets

  • Unix Domain Sockets: a.k.a. IPC sockets, allow communication between 2 processes, i.e. the server and the client, on the same machine.
    • use the file system as the address space (everything in Unix is a file) e.g. /var/run/docker/containerd/containerd.sock
  • Internet Domain Sockets: allow communication over a network, i.e. the server and the client are on different machines.
    • use the IP address and a port number as socket address, e.g. 10.20.30.40:4444;

As you can see from the system call below, they are distinguished by the domain.

Communication

Two processes may communicate with each other if each obtains a socket.

  • The server process binds its socket to an address, opens a listen channel, and then continuously loops.
  • Inside the loop, the server process is put to sleep while waiting to accept a client connection.
  • Upon accepting a client connection, the server then executes a read system call that will block wait.
  • The client connects to the server's socket via the server's address.
  • The client process then writes a message for the server process to read.

At different levels:

  • Unix domain socket: data packets are passed between two connected processes via the transport layer — either TCP or UDP.
  • Internet domain socket: data are passed between two connected processes via the transport layer and the Internet Protocol (IP) of the network layer — either TCP/IP or UDP/IP.

System Calls

int socket(int domain, int type, int protocol);

Most important domains:

  • AF_INET: IPv4
  • AF_INET6: IPv6
  • AF_UNIX / AF_LOCAL: Unix Socket

Most common types:

  • SOCK_STREAM: a stream-oriented socket (TCP)
  • SOCK_DGRAM: a datagram-oriented socket (UDP)

protocol: specify the protocol. In most cases there's only one protocol for the specified type, use 0 for protocol.

Example:

fd = socket(AF_UNIX, SOCK_STREAM, 0);

After we create the sockets on both server and client sides:

  • Server side:
    • use bind() system call to bind it to an address.
    • use listen() system call to mark the socket as passive. (by default, the socket is active)
    • use accept() system call to accept an incoming connection.
  • Client side:
    • use connect() system call to connect to a passive socket, using the same address.

Then use read() and write() system calls to communicate with the peer socket.

Remember to call close() to close the sockets.

Commands

Read more: Shell Cheatsheet - Networking