ManiAm ManiAm - 3 months ago 17
C Question

Sending variable size buffer over message queue

I wrote a simple C program in Linux that uses message queue for IPC. For simplicity

mq_send
and
mq_receive
are called in the same process.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <mqueue.h>

#define QUEUE_NAME "/test_queue2"

int main(int argc, char **argv)
{
/* initialize the queue attributes */
struct mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 30;
attr.mq_curmsgs = 0;

/* create the message queue */
mqd_t mq = mq_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0644, &attr);
if (mq < 0) {
printf("error in mq_open 1");
exit(1);
}

/* send the message */
int rc = mq_send(mq, "mani123", 8, 0); // need to include the null character too!
if (rc < 0) {
printf("error in mq_send");
exit(1);
}

// ---------------------------------------------------------------

mqd_t mq2 = mq_open(QUEUE_NAME, O_RDONLY);
if (mq2 < 0) {
printf("error in mq_open 2: %s", strerror(errno));
exit(1);
}

char rcvmsg[50];
rc = mq_receive(mq2, rcvmsg, 50, 0);
if (rc < 0) {
printf("error in mq_receive 2");
exit(1);
}

printf("%s", rcvmsg);

return 0;
}


I am sending/receiving a constant string using the message queue. Now I want to repeat this for a general buffer (array of char). I send the buffer content using
mq_send
, but my question is how
mq_receive
get the exact size of the sent buffer? Should I send the buffer size separately?

Answer

The quick answer is No, you do not need to send the message size separately.

As long as the message size no greater than the queue's mq_msgsize attribute, the size passed to mq_send is returned unchanged by mq_received.

You do not need to send the '\0' terminator, but it you don't, it will not be received either and the receiving code must set it to ensure the received string is null terminated. Be careful in this case to allow for an extra byte at the end of the destination buffer:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <mqueue.h>

#define QUEUE_NAME  "/test_queue2"

int main(int argc, char **argv) {
    /* initialize the queue attributes */
    struct mq_attr attr;
    attr.mq_flags = 0;
    attr.mq_maxmsg = 10;
    attr.mq_msgsize = 30;
    attr.mq_curmsgs = 0;

    /* create the message queue */
    mqd_t mq = mq_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0644, &attr);
    if (mq < 0) {
        printf("error in mq_open 1: %s\n", strerror(errno));
        exit(1);
    }

    /* send the message */
    const char *str = "mani123";
    int rc = mq_send(mq, str, strlen(str), 0); // no need to include the null character
    if (rc < 0) {
        printf("error in mq_send: %s\n", strerror(errno));
        exit(1);
    }

    // ---------------------------------------------------------------

    mqd_t mq2 = mq_open(QUEUE_NAME, O_RDONLY);
    if (mq2 < 0) {
        printf("error in mq_open 2: %s\n", strerror(errno));
        exit(1);
    }

    char rcvmsg[50 + 1];  // 50 is more than enough since attr.mq_msgsize = 30 
    rc = mq_receive(mq2, rcvmsg, 50, 0);
    if (rc < 0) {
        printf("error in mq_receive 2: %s\n", strerror(errno));
        exit(1);
    }
    rcvmsg[rc] = '\0';

    printf("received: %s\n", rcvmsg);

    return 0;
}

For the long answer, you will need to consider whether you will send binary messages longer than the maximum message queue's mq_msgsize attribute. If you do, you need to devise some sort of protocol where you tell the receiving side how many messages to expect and how to combine them. The length is not necessarily required, but it would be more convenient to send it along with the number of messages to simplify allocation on the receiving side.

Comments