2

I wrote a simple C program in Linux that uses message queue for IPC (similar to this post). 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");
        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?

Community
  • 1
  • 1
ManiAm
  • 1,759
  • 5
  • 24
  • 43

1 Answers1

3

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.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Thanks for the answer. I agree that when sending a string, there is no need to send the size too. But in a general buffer (consists of uint8_t) how the mq_receive know what is the size of the buffer? – ManiAm Aug 18 '16 at 18:46
  • 1
    @ManiAm: `mq_send` stores the message length in the message queue structure and `mq_receive` gets it from there. It does not matter that you are sending a string, `mq_send` does not make any assumptions about the contents of the message, it behaves the same for any kind of contents, be it `char`, `uint8_t` or whatever else. You can even pass the address of a structure, as long as it does not contain any pointers, as the pointer values would be meaningless to the receiving side. – chqrlie Aug 18 '16 at 18:52