Skip to content

Latest commit

 

History

History
194 lines (139 loc) · 5.58 KB

message_queues.md

File metadata and controls

194 lines (139 loc) · 5.58 KB

Message queues

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.

mq_open

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

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);

mq_receive

mq_close

mq_getattr

mq_setattr

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.