COMS 4995 Advanced Systems Programming

Domain sockets

Summary of UNIX IPC so far

Shared memory

  1. Multiple threads in a single process
    • Process address space is already shared among the threads
    • But we still need synchronization (see below)
  2. Related processes (i.e., parent and child)
    • Anonymous mmap: call mmap() with MAP_SHARED | MAP_ANONYMOUS and pass -1 as file descriptor
  3. Unrelated processes
    • File-backed mmap: call mmap() with MAP_SHARED and pass a valid file descriptor
    • File descriptor can be a real file returned by open() or a virtual file returned by shm_open()

Synchronization

  1. Multiple threads in a single process
    • pthread mutex, condition variable, and reader-writer lock
  2. Multiple processes
    • Shared memmory required:
      • Unnamed POSIX semaphore: sem_init(), sem_destroy()
      • We can still use pthread mutex, condition variable, and reader-writer lock, but need to initialize with PTHREAD_PROCESS_SHARED attribute
    • No shared memory required:
      • Pipes (unnamed or named) are primarily for passing data (see below) but often great for synchronization
      • Named POSIX semaphore: sem_open(), sem_close(), sem_unlink()
      • See man 7 sem_overview for naming requirements

Data passing

  1. Related processes
    • Unnamed pipe
      • created by pipe()
      • half duplex (i.e., one way communication)
  2. Unrelated processes
    • Named pipe (aka FIFO)
      • created by mkfifo()
      • still half duplex
  3. Distant processes (i.e., anywhere on the Internet)
    • TCP socket
      • full duplex
      • reliable byte stream delivery
      • high protocol overhead
      • message boundaries are not preserved
    • UDP socket
      • full duplex
      • unreliable datagram delivery
      • low protocol overhead
      • message boundaries are preserved

UNIX domain sockets

Best of pipes and sockets, but only for local processes:

  1. Unnamed pair of connected sockets for related processes
    • created by socketpair(AF_UNIX, ... )
    • just like a pipe, but full duplex
  2. Named local-only socket for unrelated processes
    • created by socket(AF_UNIX, ... )
    • represented by a special file
  3. reliable when used in datagram mode

  4. can transport special things like open file descriptor

Unnamed socket pair as Full duplex pipe

int socketpair(int domain, int type, int protocol, int sv[2]);

        // Returns 0 if OK, -1 on error

Same picture as the one for pipe() but arrows going both ways:

Figure 17.1, APUE

Example of exchanging datagram using named domain socket

Passing open file descriptors

Duplicate a file descriptor across running processes:

Figure 17.11, APUE

Real-world application: a set of worker processes collectively processing activities on a set of long running TCP connections (e.g., WebSocket: first use HTTP request/response to establish a persistent WebSocket connection, then client and server exchange JSON messages freely).

Why not use multiple threads instead of processes? That’s an option for sure, but there are advantages in both approaches; with multiple processes:

  1. One worker crashing won’t bring down the server
  2. Different processes can run as different users to have different security levels

Last updated: 2024-10-15