Lesson 09advancedIPC

Named Pipes & Message Queues

Two IPC mechanisms for unrelated processes. Named pipes (FIFOs) for byte-stream communication between any processes, and System V message queues for structured, typed message passing. Includes multi-writer FIFO, two-way FIFO, and a calculator built on message queues.

mkfifoFIFOmsggetmsgsndmsgrcvIPC
Prerequisites:08. Pipes
1

FIFO Reader

Reading from a named pipe created with mkfifo — blocks until a writer opens the other end.

02-mkfifo-example/fifo-reader.c79 lines
/*
 * fifo-reader.c — FIFO reader — reading from a named pipe
 *
 * Key concepts: mkfifo, open, read, named pipes persist in filesystem
 * Compile: gcc -o reader fifo-reader.c
 * Run:     ./prog
 */
// fifo_reader.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>      // For O_RDONLY
#include <sys/stat.h>   // For mkfifo
#include <unistd.h>     // For read and close
#include <string.h>
#include <errno.h>

const char *FIFO_NAME = "my_fifo";
const int BUFFER_SIZE = 1024;

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  FIFO Reader (Named Pipe)\n");
    printf("  Run this first, then writer in another terminal\n");
    printf("══════════════════════════════════════\n\n");
    int fd;
    char buffer[BUFFER_SIZE];

    // Create the FIFO (named pipe) if it does not exist
    if (mkfifo(FIFO_NAME, 0666) == -1) {
        if (errno != EEXIST) { // It's okay if the FIFO already exists
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    }

    printf("[Reader PID %d] FIFO '%s' created/exists.\n", getpid(), FIFO_NAME);

    // Open the FIFO for reading
    fd = open(FIFO_NAME, O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    printf("[Reader] Connected (fd=%d). Waiting for messages...\n\n", fd);

    while (1) {
        // Read from the FIFO
        ssize_t bytesRead = read(fd, buffer, BUFFER_SIZE);
        if (bytesRead == -1) {
            perror("read");
            break;
        } else if (bytesRead == 0) {
            // No more writers; exit
            printf("[Reader] read() returned 0 — writer closed the FIFO (EOF).\n");
            break;
        }

        printf("[Reader] Received %ld bytes: \"%s\"\n", (long)bytesRead, buffer);

        // Exit condition
        if (strcmp(buffer, "exit") == 0) {
            printf("Reader: Exit signal received. Exiting.\n");
            break;
        }
    }

    // Close the FIFO
    close(fd);
    //this will delete the FIFO file and its important to do it!!!
    // ONLY ONE PROCESS SHOULD DO THIS
    if(unlink(FIFO_NAME) == -1){
        perror("unlink");
        exit(EXIT_FAILURE);
    }
    return 0;
}
2

FIFO Writer

Writing to a named pipe — demonstrates how data flows to the reader process.

02-mkfifo-example/fifo-writer.c95 lines
3

Multiple FIFO Writers

Multiple writer processes sending data to the same named pipe concurrently.

03-mk-fifo-multi-writers/multi-writer.c86 lines
4

Multi-Writer Reader

A reader that receives interleaved data from multiple writers on one FIFO.

03-mk-fifo-multi-writers/reader.c70 lines
/*
 * reader.c — Reader for multi-writer FIFO
 *
 * Key concepts: Reading from FIFO with multiple writers
 * Compile: gcc -o reader reader.c
 * Run:     ./prog
 */
// fifo_reader_single.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>      // For O_RDONLY
#include <sys/stat.h>   // For mkfifo
#include <unistd.h>     // For close
#include <string.h>
#include <errno.h>

const char *FIFO_NAME = "multi_fifo";
const int BUFFER_SIZE = 1024;

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  Reader for multi-writer FIFO\n");
    printf("══════════════════════════════════════\n\n");
    FILE *fp;
    char buffer[BUFFER_SIZE];
    int writer_count = 0;

    // Create the FIFO (named pipe) if it does not exist
    if (mkfifo(FIFO_NAME, 0666) == -1) {
        if (errno != EEXIST) { // It's okay if the FIFO already exists
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    }

    printf("Reader: FIFO '%s' created/opened for reading.\n", FIFO_NAME);

    // Open the FIFO for reading using fopen
    fp = fopen(FIFO_NAME, "r");
    if (fp == NULL) {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    printf("Reader: FIFO opened. Waiting for messages...\n");

    while (fgets(buffer, BUFFER_SIZE, fp) != NULL) {
        // Remove newline character
        buffer[strcspn(buffer, "\n")] = '\0';

        printf("Reader: Received -> %s\n", buffer);

        // Optional: Exit condition if a specific message is received
        if (strcmp(buffer, "exit") == 0) {
            printf("Reader: Exit signal received. Exiting.\n");
            break;
        }
    }

    // Close the FIFO
    fclose(fp);



        //this will delete the FIFO file and its important to do it!!!
     unlink(FIFO_NAME);
    return 0;
}
5

Two-Way FIFO: Process A

First half of bidirectional FIFO communication — sends on one pipe, receives on another.

04-mk-fifo-two-way/process_a.c111 lines
6

Two-Way FIFO: Process B

Second half — mirrors process A for full-duplex named-pipe communication.

04-mk-fifo-two-way/process_b.c104 lines
7

Basic Message Queue

Parent-child communication using System V message queues with msgget, msgsnd, and msgrcv.

05-msg-que-basic/aba_yeled.c103 lines
Expected Outputclick Run to execute live
========================================
  Basic message queue — parent-child
========================================

Child received message: Hello from Parent!

========================================
  Basic message queue — parent-child
========================================

Parent sent message: Hello from Parent!
8

Extended Message Queue

Expanded message queue example with typed messages and structured data.

05-msg-que-basic/02_aba_yeled.c95 lines
Expected Outputclick Run to execute live
========================================
  Extended message queue with typed me
========================================

Child received message of type 2: Message Type 2

========================================
  Extended message queue with typed me
========================================

Parent sent message of type 1: Message Type 1
Parent sent message of type 2: Message Type 2
9

Bidirectional Message Queue

Two-way communication on a single message queue using different message types for each direction.

05-msg-que-basic/03_bidirection.c104 lines
Expected Outputclick Run to execute live
========================================
  Bidirectional message queue communic
========================================

Child received from parent: Hello from Parent!
Child sent to parent: Hello from Child!

========================================
  Bidirectional message queue communic
========================================

Parent sent to child: Hello from Parent!
Parent received from child: Hello from Child!
10

IPC Cleanup with ipcrm

Cleaning up System V IPC resources (message queues, shared memory, semaphores) with msgctl and ipcrm.

06-ipcm-ipcrm-removing.c67 lines
/*
 * 06-ipcm-ipcrm-removing.c — Cleaning up IPC resources — ipcs and ipcrm
 *
 * Key concepts: msgctl IPC_RMID, cleaning up message queues, ipcs command
 * Compile: gcc -o cleanup 06-ipcm-ipcrm-removing.c
 * Run:     ./prog
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>


// THIS PROGRAM DOESNT!!! DELETE THE MESSAGE QUEUE
// so we will have to do it manually

//ipcs -q
//example output:
/*
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x12345    123456     user       644        0            0           
*/

//removing:
//ipcrm -q 123456

// run again:
//ipcs -q



struct my_msgbuf {
    long mtype;
    char mtext[100];
};

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  Cleaning up IPC resources — ipcs a\n");
    printf("══════════════════════════════════════\n\n");
    key_t key;
    int msgid;
    struct my_msgbuf buf;

    // Generate unique key
      key = ftok("/tmp", 65); 
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // Create message queue
    msgid = msgget(key, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    printf("Message Queue created with msgid: %d\n", msgid);

    // Program ends without deleting the message queue
    return 0;
}
Expected Outputclick Run to execute live
========================================
  Cleaning up IPC resources — ipcs a
========================================

Message Queue created with msgid: 3
11

Message Queue Sender

A standalone sender program that pushes messages onto a System V message queue.

07-msg-que-two-progs/sender.c73 lines
/*
 * sender.c — Message queue sender (separate program)
 *
 * Key concepts: msgsnd, cross-program IPC via shared queue key
 * Compile: gcc -o sender sender.c
 * Run:     ./prog
 */
// sender.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>


int const MSG_TYPE_EXIT =  3;
struct my_msgbuf {
    long mtype; // Message type
    char mtext[256]; // Message data
};

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  Message queue sender (separate progr\n");
    printf("══════════════════════════════════════\n\n");
    key_t key;
    int msgid;
    struct my_msgbuf buf;

    // Generate the same unique key
       key = ftok("/tmp", 65); 
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // Access the message queue
    msgid = msgget(key, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    printf("Sender: Enter messages to send. Type 'exit' to quit.\n");

    while (1) {
        printf("Sender: ");
        fflush(stdout);
        fgets(buf.mtext, sizeof(buf.mtext), stdin);
        buf.mtext[strcspn(buf.mtext, "\n")] = '\0'; // Remove newline

        if (strcmp(buf.mtext, "exit") == 0) {
            buf.mtype = MSG_TYPE_EXIT;
        } else {
            buf.mtype = 1; // Default message type
        }

        // Send the message
        if (msgsnd(msgid, &buf, strlen(buf.mtext) + 1, 0) == -1) {
            perror("msgsnd");
            exit(EXIT_FAILURE);
        }

        if (buf.mtype == MSG_TYPE_EXIT) {
            printf("Sender: Exit message sent. Exiting.\n");
            break;
        }
    }

    return 0;
}
12

Message Queue Receiver

A standalone receiver that pulls messages from the queue — run alongside the sender.

07-msg-que-two-progs/receiver.c70 lines
/*
 * receiver.c — Message queue receiver (separate program)
 *
 * Key concepts: msgrcv, blocking receive, message types
 * Compile: gcc -o receiver receiver.c
 * Run:     ./prog
 */
// receiver.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
int const MSG_TYPE_EXIT =  3;

struct my_msgbuf {
    long mtype; // Message type
    char mtext[256]; // Message data
};

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  Message queue receiver (separate pro\n");
    printf("══════════════════════════════════════\n\n");
    key_t key;
    int msgid;
    struct my_msgbuf buf;

    // Generate unique key using ftok
       key = ftok("/tmp", 65); 
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // Create or access the message queue
    msgid = msgget(key, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    printf("Receiver: Waiting for messages...\n");

    while (1) {
        // Receive any message
        if (msgrcv(msgid, &buf, sizeof(buf.mtext), 0, 0) == -1) {
            perror("msgrcv");
            exit(EXIT_FAILURE);
        }

        // Check for exit message
        if (buf.mtype == MSG_TYPE_EXIT) {
            printf("Receiver: Exit message received. Exiting.\n");
            break;
        }

        printf("Receiver: Received message: %s\n", buf.mtext);
    }

    // Cleanup: Remove the message queue
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        exit(EXIT_FAILURE);
    }

    return 0;
}
13

Calculator Sender

Sends arithmetic expressions through a message queue to a calculator receiver process.

08-calc-que/calc_sender.c152 lines
14

Calculator Receiver

Receives expressions from the message queue, evaluates them, and sends results back.

08-calc-que/calc_receiver.c140 lines

Open Full Terminal

Get a Linux terminal with all 14 files from this lesson pre-loaded. Compile, run, and experiment freely.