Linux IPC
56 – TLPI
Beginner
What You Will Learn
In this part you will understand what a socket is, how it fits into the bigger picture of Linux IPC, and how two applications use the basic socket() system call to start communicating. No networking knowledge is assumed — we build from the ground up.
A socket is an endpoint for communication. Think of it like a telephone handset — each party in a conversation needs one, and the two handsets together form the communication channel.
Sockets are a form of Inter-Process Communication (IPC). Unlike pipes (which only work between related processes on the same machine), sockets can be used:
- Between two processes on the same host, or
- Between processes on different hosts connected by a network.
The first popular socket implementation appeared in 4.2BSD (1983). Today the API is standardised by POSIX.1g (ratified in 2001, now covered by SUSv3) and is available on virtually every UNIX and Linux system.
| Process A (Client) Socket FD
|
data flows both ways
Same host (kernel pipe)
or Network (TCP/UDP) |
Process B (Server) Socket FD
|
Each process holds a file descriptor that refers to its socket. The kernel handles the actual data transfer underneath.
The typical steps when two applications communicate with sockets are:
| Step | Server Side | Client Side |
|---|---|---|
| 1 | Call socket() — get a file descriptor |
Call socket() — get a file descriptor |
| 2 | Call bind() — attach to a well-known address |
(no bind needed usually) |
| 3 | Call listen() — mark socket as passive |
Call connect() — reach the server address |
| 4 | Call accept() — receive a client connection |
Connection established |
| 5 | read() / write() / send() / recv() |
read() / write() / send() / recv() |
| 6 | close() |
close() |
The server publishes a well-known address so clients know where to connect. This is similar to a phone number — clients dial (connect) to it.
The very first step for any socket program is creating a socket with socket():
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
/*
* Returns: file descriptor on success, -1 on error
*
* domain – communication domain (AF_UNIX, AF_INET, AF_INET6)
* type – socket type (SOCK_STREAM, SOCK_DGRAM)
* protocol – usually 0 (kernel picks the right protocol)
*/
The return value is an ordinary file descriptor. This means you can use standard I/O calls like read(), write(), and close() on a socket, just like a regular file or pipe.
Minimal example — creating a TCP socket:
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
int main(void)
{
int sockfd;
/* AF_INET = IPv4 domain
* SOCK_STREAM = reliable, connection-oriented (TCP)
* 0 = let kernel choose protocol (TCP here)
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
printf("Socket created successfully, fd = %d\n", sockfd);
/* The fd behaves like a file — close it when done */
close(sockfd);
return 0;
}
Compile and run:
gcc -o create_socket create_socket.c
./create_socket
# Output: Socket created successfully, fd = 3
| IPC Mechanism | Same Host Only? | Unrelated Processes? | Network Capable? |
|---|---|---|---|
| Pipes | Yes | No (related only) | No |
| FIFOs | Yes | Yes | No |
| Message Queues (POSIX) | Yes | Yes | No |
| Sockets (AF_UNIX) | Yes | Yes | No |
| Sockets (AF_INET/6) | No — cross-host | Yes | Yes ✔ |
Q1. What is a socket in Linux?
A socket is a kernel object that acts as a communication endpoint. It is represented as a file descriptor in user space, allowing standard read()/write() operations. Two sockets (one per communicating process) form a channel for data exchange either within the same host or across a network.
Q2. How is a socket different from a pipe?
A pipe is unidirectional and only works between related processes on the same host. A socket is bidirectional, can connect unrelated processes, and — in the Internet domain — can communicate over a network between different machines.
Q3. What does the socket() system call return and why is that useful?
It returns an integer file descriptor. Because Linux treats everything as a file, this means you can use read(), write(), select(), poll(), and close() on a socket without needing socket-specific wrappers for basic I/O.
Q4. When does a server need to call bind() but a client usually does not?
A server needs a stable, well-known address so clients can find it — similar to a fixed phone number. A client connects outward; the kernel automatically assigns it an ephemeral address/port, so explicit binding is not required.
Q5. What is POSIX.1g and why does it matter for socket programming?
POSIX.1g is the POSIX standard that formally specifies the sockets API. Ratified in 2001 and now part of SUSv3, it ensures that socket code written on Linux will behave consistently on other POSIX-compliant systems such as macOS, FreeBSD, and Solaris.
Learn about AF_UNIX, AF_INET, and AF_INET6 and when to use each.
