Message queues are another form of IPC.
Linux implements a new way to program the message queues. The interface is called as mq_overview
.
Header file to include <mqueue.h>
.
The manual page of mq_overview
defines a set of API.
API Name | description |
---|---|
mq_open | create / open a message queue |
mq_send | write a message to a queue |
mq_receive | read a message from a queue |
mq_close | close a message queue |
mq_unlink | removes a message queue name and marks it for deletion |
mq_getattr | get attributes of message queue |
mq_setattr | set attributes of message queue |
To use the message queues, link with -lrt
.
message queues are created and opened using mq_open
. This function returns a message queue descriptor of type mqd_t
which is a file descriptor. This file descriptor can be used as an input to the select
system call to selectively wait.
Each message queue is identified by a name of the form /name. The maximum length of the name field is 255 bytes.
The prototype of the mq_open
is as follows:
mqd_t mq_open(const char *name, int oflag);
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
As we can see that the above are two different API declarations. This means that the mq_open
must be a variable argument function and the prototypes are given to simply the usage.
Here is the example program that uses the mq_open
API.
mqd_t server_fd;
struct mq_attr mq_attr;
server_fd = mq_open("/mq1", O_CREAT | O_RDWR, 0644, &mq_attr);
if (server_fd < 0) {
printf("failed to open server fd\n");
perror("mq_open");
return -1;
}
printf("server fd %d\n", server_fd);
The name
is the name of the message queue that we are going to use. If the message queue is already not created, it has to be created. To create it, we must provide the following to the oflag
field: The O_RDWR | O_CREAT
. Meaning, create a message queue (O_CREAT
) for sending and receiving (O_RDWR
).
If the queue is already created, we just have to open it. The process can simply open it for receive only or cna be opened in sending and receiving modes.
In the create mode of operation, the mode argument must contain the permission bits. The permissions bits are usually 0644
. Along with the permission bits, one must also specify the attributes of the message queue. The attribute structure struct mq_attr
is to be filled. The structure looks as the following:
struct mq_attr {
long mq_flags; // 0 or O_NONBLOCK
long mq_maxmsg; // maximum number of messages that go into the queue
long mq_msgsize; // maximum message size in bytes
long mq_curmsg; // number of messages currently queued
};
The server program calls the mq_open
with the following args. Usually the server program creates a message queue and the client program opens the message queue.
The mq_getattr
is used to get attributes of the message queue into the above structure and mq_setattr
is used to set attributes of the message queue.
mq_send
sends a message to the message queue. Here is the prototype.
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
Below is one example of the message queues. The server side creates a message queue with mq_open
and sets up the queues. The server then waits for the message in mq_receive
.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <errno.h>
mqd_t server_fd;
int len;
struct mq_attr attr;
int main()
{
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 64;
attr.mq_curmsgs = 0;
server_fd = mq_open("/mq1", O_CREAT | O_RDWR, 0644, &attr);
if (server_fd < 0) {
printf("failed to open server fd\n");
perror("mq_open");
return -1;
}
struct mq_attr new_attr;
mq_getattr(server_fd, &new_attr);
printf("flags %d maxmsg %d msgsize %d curmsg %d\n",
new_attr.mq_flags,
new_attr.mq_maxmsg,
new_attr.mq_msgsize,
new_attr.mq_curmsgs);
printf("server fd %d\n", server_fd);
while (1) {
char buf[8192 * 2];
len = mq_receive(server_fd, buf, sizeof(buf), NULL);
if (len < 0) {
printf("failed to receive from the mqueue\n");
perror("mq_receive");
return -1;
}
printf("received msg with len %u message %s\n", len, buf);
}
mq_close(server_fd);
return 0;
}
Example: message queue server program
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <errno.h>
mqd_t client_fd;
int len;
struct mq_attr attr;
int main()
{
client_fd = mq_open("/mq1", O_RDWR);
if (client_fd < 0) {
printf("failed to open server fd\n");
perror("mq_open");
return -1;
}
char buf[8192 * 2];
while (1) {
strcpy(buf, "Hello");
len = mq_send(client_fd, buf, strlen(buf) + 1, 1);
if (len < 0) {
printf("failed to send to the mqueue\n");
perror("mq_send");
return -1;
}
sleep(1);
}
mq_close(client_fd);
return 0;
}
Example: message queue client program
Compile the server program as gcc mq_server.c -lrt -o mq_server
and client program as gcc mq_client.c -lrt -o mq_client
. Run the server program first and then the client to receive the messages.