1 of 4
Architecture
Intermediate
Linux IPC
What This Tutorial Covers
This part explains what the SysV Message Queue File Server–Client application does, why it is designed the way it is, what message types are used, and how the overall communication flow looks. No code details yet — just the big picture you need before reading the code.
The application lets a client send the name of a file to a server. The server reads that file and sends the contents back — all through System V message queues. It is a classic IPC example that shows real-world patterns used in embedded Linux and server software.
Key Terms in This Tutorial
A System V message queue is a kernel-maintained linked list of messages. Each message has a type (a positive long integer) and a data body. Processes can send and receive messages independently — unlike pipes which are strictly one-way byte streams.
Key advantages over pipes for this file-server scenario:
- Message boundaries are preserved — each send/receive is one complete message, not a byte stream.
- Multiple clients can write to one server queue using different message types.
- Selective receive — a process can pick messages of a specific type, ignoring others.
- Bidirectional — the server replies directly to each client’s private queue.
msgctl(id, IPC_RMID, NULL) or system reboot. This is different from pipes which disappear when all file descriptors are closed.The application has two programs: a server and a client.
| Role | What It Does | Queue Used |
|---|---|---|
| Server | Waits for file requests from any client. Opens the requested file and sends its contents back in chunks. | One well-known server queue (fixed key) |
| Client | Sends a file pathname to the server. Receives file contents and prints them. | Its own private queue (IPC_PRIVATE key) |
The server runs continuously and handles multiple clients at the same time by forking a child process for each request.
Below is a visual showing how server, clients, and message queues relate to each other:
IPC_PRIVATESERVER_KEYIPC_PRIVATEThe important design point: every client has its own reply queue. The client passes its queue ID inside the request message so the server knows where to send the reply.
Both request and response messages use a long mtype field. This field controls which process receives the message when multiple messages are in a queue.
Request Message
| Field | Type | Purpose |
|---|---|---|
mtype |
long | Any positive value (e.g. 1) — server reads all types |
clientId |
int | Queue ID of this client’s private reply queue |
pathname |
char[] | Path of the file the client wants |
Response Message Types (Server → Client)
| Constant | Meaning | Data field |
|---|---|---|
RESP_MT_FAILURE |
Server could not open the file | Error description string |
RESP_MT_DATA |
A chunk of the file contents | Up to RESP_MSG_SIZE bytes of file data |
RESP_MT_END |
End of file — no more data | Zero-length (empty) |
mtype values is the clean SysV MQ way to do this — no extra flag fields needed.| Step | Who | What Happens |
|---|---|---|
| 1 | Server startup | Creates server queue with well-known key SERVER_KEY. Starts waiting for requests. |
| 2 | Client startup | Creates its own private queue with IPC_PRIVATE. Registers atexit() handler to delete this queue on exit. |
| 3 | Client → Server | Client sends a request message to the server queue. The message contains the file pathname and the client’s queue ID. |
| 4 | Server | Server receives the request and fork()s a child process to handle it. Parent loops back to wait for the next request. |
| 5 | Server child | Tries to open the requested file. If it fails, sends RESP_MT_FAILURE to the client queue. |
| 6 | Server child | If file opened OK, reads chunks and sends each as a RESP_MT_DATA message to client queue. |
| 7 | Server child | After all data sent, sends one RESP_MT_END message (zero data) and exits. |
| 8 | Client | Checks first response. If RESP_MT_FAILURE, prints error and exits. Otherwise loops receiving RESP_MT_DATA messages until it gets RESP_MT_END. |
IPC_PRIVATE is a special key that tells the kernel: “create a brand new queue that nobody else knows about yet.” No other process can accidentally connect to it because it has no fixed key.
This solves a key problem: if two clients both tried to receive from a shared response queue, they might steal each other’s messages. With IPC_PRIVATE:
- Each client gets a unique queue ID returned by
msgget(). - The client puts this ID in the request so the server knows exactly where to reply.
- No other process knows this ID, so only this client gets the responses.
IPC_PRIVATE queues are not named, they must be explicitly deleted. The client registers a cleanup function with atexit() so the queue is removed even if the client exits abnormally.Before writing server or client code, you define the message structures that both sides share (usually in a header file):
/* svmsg_file.h — shared header for server and client */
#include <sys/msg.h>
#include <fcntl.h>
#define SERVER_KEY 0x1aaaaaa1 /* well-known key for server queue */
#define RESP_MSG_SIZE 8192 /* max bytes of file data per message */
/* Response message types */
#define RESP_MT_FAILURE 1 /* server could not open file */
#define RESP_MT_DATA 2 /* message contains file data */
#define RESP_MT_END 3 /* end of file, no more data */
/* Request message: client → server */
struct requestMsg {
long mtype; /* message type (always 1) */
int clientId; /* client's reply queue ID */
char pathname[PATH_MAX]; /* file to serve */
};
#define REQ_MSG_SIZE (sizeof(struct requestMsg) - sizeof(long))
/* Response message: server → client */
struct responseMsg {
long mtype; /* RESP_MT_FAILURE/DATA/END */
char data[RESP_MSG_SIZE]; /* file data or error text */
};
The size argument to msgsnd/msgrcv excludes the leading mtype field. That is why macros like REQ_MSG_SIZE subtract sizeof(long).
In the next part we go deeper into the concurrent server design — how forking works, how zombie processes are prevented, and how SIGCHLD is handled.
- Why does a SysV message queue file server use
IPC_PRIVATEfor client reply queues? - What are the three response message types used in this application and when is each sent?
- Why does the client embed its queue ID inside the request message?
- What is the difference between
SERVER_KEYandIPC_PRIVATE? - Why must the client delete its queue using
atexit()instead of a normal close call? - How does the server distinguish between multiple clients if all requests go to one queue?
- What problem would arise if all clients shared a single response queue?
