passing file descriptors between processes
A file descriptor is just a small integer — fd 3, fd 4 — that indexes into your process's own private table of open files and sockets. So you might think you could just send the number 3 to another process and it could use it. You cannot: fd 3 in your process and fd 3 in theirs point to completely different things, because each process has its own descriptor table. The number is meaningless outside the process that owns it.
Yet there is a real, almost surprising kernel feature that lets one process hand a working open file or socket to another. Over a Unix-domain socket, the sender attaches the descriptor as 'ancillary data' (the mechanism is called SCM_RIGHTS) using sendmsg(); the receiver collects it with recvmsg(). What actually crosses is not the integer — the kernel duplicates the underlying open-file object and installs a fresh descriptor (likely a different number) in the receiver's table that refers to the very same open file, socket, or pipe. The receiver can now read() and write() it as if it had opened it itself, sharing the same file offset and connection.
This unlocks designs that are otherwise impossible. A privileged parent can open a restricted file or bind a low-numbered port, then pass the ready descriptor to an unprivileged child that could never have opened it. A master process can accept() incoming network connections and hand each connected socket to a pool of worker processes to serve — this is how some high-performance servers distribute load. The caveat to keep straight: this only works over a Unix-domain socket on the same machine, and it transfers a capability (an open connection), not a path or a name — the receiver gets the live object, fresh descriptor number and all.
Parent opens fd for a network connection, then sendmsg() with SCM_RIGHTS over a Unix socket → child's recvmsg() yields, say, fd 7 referring to the same connection. The child serves it directly; the integer 3 was never what travelled.
The kernel duplicates the open object into the receiver's table. The descriptor number changes; the underlying connection is shared.
You cannot pass a descriptor by just sending its integer value — the number indexes a per-process table and means nothing elsewhere. Real fd passing needs SCM_RIGHTS over a Unix-domain socket, and what arrives is a new number for the same open object.