The Most Comprehensive Guide to Linux Interprocess Communication (IPC) – All Methods Explained
This article provides a detailed, step‑by‑step overview of every Linux interprocess communication mechanism—including pipes, signals, files, semaphores, shared memory, message queues, sockets, and Unix domain sockets—complete with concepts, usage scenarios, diagrams, and full code examples.
All Linux Interprocess Communication (IPC) Mechanisms
1. Pipe
Pipes provide a simple byte‑stream channel between processes. Two types exist:
Anonymous Pipe
Used between related processes (e.g., parent‑child). Data flows in one direction; a second pipe is needed for bidirectional communication.
#include <unistd.h>
int main() {
int pipefd[2];
pipe(pipefd); // create anonymous pipe
if (fork() == 0) { // child
close(pipefd[1]); // close write end
read(pipefd[0], buf, 5);
} else { // parent
close(pipefd[0]); // close read end
write(pipefd[1], "hello", 5);
}
return 0;
}Named Pipe (FIFO)
A FIFO is a special file that can be opened by unrelated processes. It appears in the filesystem with a pathname.
// server.c
int main() {
const char *fifoPath = "/tmp/my_fifo";
mkfifo(fifoPath, 0666);
char buf[1024];
int fd;
while (1) {
fd = open(fifoPath, O_RDONLY);
read(fd, buf, sizeof(buf));
printf("Received: %s
", buf);
close(fd);
}
return 0;
}
// client.c
int main() {
const char *fifoPath = "/tmp/my_fifo";
char buf[1024];
printf("Enter message: ");
fgets(buf, sizeof(buf), stdin);
int fd = open(fifoPath, O_WRONLY);
write(fd, buf, strlen(buf) + 1);
close(fd);
return 0;
}2. Signals
Signals are asynchronous notifications sent by the kernel or another process. They are used for exception handling, external interrupts (e.g., Ctrl+C → SIGINT), process control, timers, and child‑process status changes.
List of common signals can be displayed with kill -l:
~$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
...Example of handling SIGINT:
void signal_handler(int signal_num) {
printf("Received signal: %d
", signal_num);
}
int main() {
signal(SIGINT, signal_handler);
while (1) { sleep(1); }
return 0;
}3. Files
Regular files can act as a persistent IPC medium: processes read and write the same file to exchange data.
Note: concurrent writers can cause race conditions; file locks (fcntl or flock) should be used to ensure consistency.
// writer process
int main() {
const char *file = "/tmp/ipc_file";
int fd = open(file, O_RDWR | O_CREAT, 0666);
write(fd, "Hello from Process A", 20);
close(fd);
return 0;
}
// reader process
int main() {
const char *file = "/tmp/ipc_file";
int fd = open(file, O_RDWR | O_CREAT, 0666);
char buf[50];
read(fd, buf, 20);
close(fd);
return 0;
}File‑locking example (using fcntl):
struct flock fl;
fl.l_type = F_WRLCK; // write lock
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0; // whole file
fcntl(fd, F_SETLKW, &fl);
// ... critical section ...
fl.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &fl);4. Semaphores
Semaphores provide counting‑based synchronization. POSIX semaphores are preferred for their simple API.
Anonymous Semaphore
Lives in memory, visible only to related processes.
Named Semaphore
Has a filesystem pathname and can be shared between unrelated processes.
Example of two processes using a named semaphore to serialize access to a log file:
// process1.c
int main() {
FILE *logFile = fopen("logfile.txt", "a");
sem_t *sem = sem_open("/log_semaphore", O_CREAT, 0644, 1);
sem_wait(sem);
fprintf(logFile, "Log message from Process 1
");
fflush(logFile);
sem_post(sem);
sem_close(sem);
fclose(logFile);
return 0;
}
// process2.c (identical, writes Process 2)Comparison of API differences between anonymous and named semaphores is shown in the following diagram:
5. Shared Memory
Shared memory offers the highest‑throughput IPC because data does not need to pass through the kernel for each read/write.
Anonymous Shared Memory
Created with
mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0). Suitable for parent‑child communication.
File‑backed Shared Memory
A regular file is mapped with mmap (using a file descriptor). Data persists on disk and can be shared by unrelated processes.
POSIX Shared Memory
Created with shm_open and mapped with mmap. Provides named objects without a backing file.
System V Shared Memory
Uses shmget, shmat, shmdt, and shmctl. Older API but still widely supported.
Example of two unrelated processes communicating via POSIX shared memory and a named semaphore:
#define SHM_NAME "/example_shm"
#define SHM_SIZE 4096
#define SEM_NAME "/example_sem"
int main() {
int shm_fd = shm_open(SHM_NAME, O_CREAT|O_RDWR, 0666);
ftruncate(shm_fd, SHM_SIZE);
void *ptr = mmap(0, SHM_SIZE, PROT_WRITE|PROT_READ, MAP_SHARED, shm_fd, 0);
sem_t *sem = sem_open(SEM_NAME, O_CREAT, 0666, 1);
sem_wait(sem);
strcpy(ptr, "Hello from writer process!");
printf("Writer wrote: %s
", (char*)ptr);
sem_post(sem);
munmap(ptr, SHM_SIZE);
close(shm_fd);
sem_close(sem);
return 0;
}
// Reader performs the symmetric steps, using sem_wait/sem_post around a read.6. Message Queues
Message queues allow asynchronous, typed messages to be sent between processes. System V API is used.
struct message { long mtype; char mtext[100]; };
int main() {
key_t key = ftok("queuefile", 65);
int msgid = msgget(key, 0666|IPC_CREAT);
struct message msg;
msg.mtype = 1;
sprintf(msg.mtext, "Hello World");
msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
printf("Sent: %s
", msg.mtext);
return 0;
}
// Receiver uses msgrcv and finally msgctl(..., IPC_RMID, NULL) to remove the queue.7. Sockets
Sockets support both local IPC and network communication. TCP (stream‑oriented) and UDP (datagram‑oriented) are the most common protocols.
Simple TCP server/client example:
// server.c
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[1024] = {0};
server_fd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr *)&address, sizeof(address));
listen(server_fd, 3);
while (1) {
new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen);
read(new_socket, buffer, 1024);
printf("Message from client: %s
", buffer);
close(new_socket);
}
close(server_fd);
return 0;
}
// client.c
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
sock = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
char *message = "Hello from the client!";
send(sock, message, strlen(message), 0);
close(sock);
return 0;
}8. Unix Domain Sockets
Unix domain sockets provide high‑performance local IPC because data never traverses the network stack.
// server.c
int main() {
int server_fd, client_socket;
struct sockaddr_un address;
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "/tmp/unix_socket");
bind(server_fd, (struct sockaddr *)&address, sizeof(address));
listen(server_fd, 5);
while (1) {
client_socket = accept(server_fd, NULL, NULL);
char buffer[100];
read(client_socket, buffer, sizeof(buffer));
printf("Received: %s
", buffer);
close(client_socket);
}
close(server_fd);
unlink("/tmp/unix_socket");
return 0;
}
// client.c
int main() {
int sock;
struct sockaddr_un address;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "/tmp/unix_socket");
connect(sock, (struct sockaddr *)&address, sizeof(address));
char *message = "Hello from the client!";
write(sock, message, strlen(message));
close(sock);
return 0;
}Important notes: the socket path is a filesystem entry, it must be accessible, and the file should be removed after use.
Conclusion
Linux offers a rich set of IPC mechanisms, each suited to different scenarios—from simple one‑way data streams with pipes to high‑throughput shared memory and flexible message queues. Selecting the appropriate method simplifies process coordination and improves application performance.
If you have mastered these basics, congratulations! Otherwise, feel free to ask questions in the comments to deepen your understanding.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
