1

Here I have to send and receive dynamic data using a SysV message queue.

so in structure filed i have dynamic memory allocation char * because its size may be varies.

so how can i receive this type of message at receiver side.

Please let me know how can i send dynamic length of data with message queue.

I am getting problem in this i posted my code below.

send.c

/*filename   : send.c
 *To compile : gcc send.c -o send
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct my_msgbuf {
    long mtype;
    char *mtext;
};

int main(void)
{
    struct my_msgbuf buf;
    int msqid;
    key_t key;
    static int count = 0;
    char temp[5];
    int run = 1;
    if ((key = ftok("send.c", 'B')) == -1) {
        perror("ftok");
        exit(1);
    }

    printf("send.c Key is = %d\n",key);

    if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) {
        perror("msgget");
        exit(1);
    }

    printf("Enter lines of text, ^D to quit:\n");

    buf.mtype = 1; /* we don't really care in this case */
    int ret = -1;
    while(run) {
        count++;
        buf.mtext = malloc(50);
        strcpy(buf.mtext,"Hi hello test message here");
        snprintf(temp, sizeof (temp), "%d",count);
        strcat(buf.mtext,temp);
        int len = strlen(buf.mtext);
        /* ditch newline at end, if it exists */
        if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
        if (msgsnd(msqid, &buf, len+1, IPC_NOWAIT) == -1) /* +1 for '\0' */
        perror("msgsnd");
        if(count == 100)
            run = 0;
        usleep(1000000);
    }

    if (msgctl(msqid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        exit(1);
    }

    return 0;
}

receive.c

/* filename   : receive.c
 * To compile : gcc receive.c -o receive
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct my_msgbuf {
    long mtype;
    char *mtext;
};

int main(void)
{
    struct my_msgbuf buf;
    int msqid;
    key_t key;

    if ((key = ftok("send.c", 'B')) == -1) {  /* same key as send.c */
        perror("ftok");
        exit(1);
    }

    if ((msqid = msgget(key, 0644)) == -1) { /* connect to the queue */
        perror("msgget");
        exit(1);
    }

    printf("test: ready to receive messages, captain.\n");

    for(;;) { /* receive never quits! */
        buf.mtext = malloc(50);
        if (msgrcv(msqid, &buf, 50, 0, 0) == -1) {
            perror("msgrcv");
            exit(1);
        }
        printf("test: \"%s\"\n", buf.mtext);
    }

    return 0;
}
user1089679
  • 2,328
  • 8
  • 41
  • 51

1 Answers1

4

A couple of ways to solve your problem are:

  1. Make the messages fixed length.
  2. Send a fixed length "header" that includes the message length.
  3. Send a terminator, since you seem to send strings include the terminating '\0'.

Edit: How to use msgsnd and msgrcv:

Your usage of the structure and msgsnd is wrong, as the function expects the whole message to be one continuous memory area. Examples such as this use a structure with normal fields in it, or like this (at the bottom) which uses a fixed length string array.

You can send dynamic data having the structure size being dynamic as well. The trick here is to use a small fixed-size structure, and allocate more data than is needed.

Lets rewrite parts of your example sender code:

struct my_msgbuf {
    long   mtype;     /* Message type, must be > 0 */
    char   mtext[1];  /* Some compilers allow `char mtext[0]` */
};

/* ... */


int count = 0;
while (count < 100) {
    count++;

    /* Put string in a temporary place */
    char tmp[64];
    snprintf(tmp, sizeof(tmp), "Hi hello test message here %d", count);

    /* +1 for the terminating '\0' */
    size_t msgsz = strlen(tmp) + 1;

    /* Allocate structure, and memory for the string, in one go */
    struct my_msgbuf *buf = malloc(sizeof(struct my_msgbuf) + msgsz);

    /* Set up the message structure */
    buf->mtype = 1;
    memcpy(buf->mtext, tmp, msgsz);

    /* And send the message */
    msgsnd(msgid, buf, msgsz, IPC_NOWAIT);

    /* Remember to free the allocated memory */
    free(buf);
}

The above code handles sending of dynamic strings, as long as the are less than 63 characters (the size of the temporary string minus one).

Unfortunately msgrcv doesn't really support receiving of dynamically sized data. This can be helped by not using the MSG_NOERROR flag, and check for error E2BIG and then using realloc to get a bigger message buffer.

Something like this for receiving:

/* Should start with larger allocation, using small just for example */
size_t msgsz = 8;
struct my_msgbuf *buf = NULL;

for (;;) {
    /* Allocate if `buf`  is NULL, otherwise reallocate */
    buf = realloc(buf, msgsz);

    /* Receive message */
    ssize_t rsz = msgrcv(msgid, buf, msgsz, 1, 0);

    if (rsz == -1) {
        if (errno == E2BIG)
            msgsz += 8;  /* Increase size to reallocate and try again */
        else {
            perror("msgrcv");
            break;
        }
    } else {
        /* Can use `buf->mtext` as a string, as it already is zero-terminated */
        printf("Received message of length %d bytes: \"%s\""\n", rsz, buf->mtext);
        break;
    }
}

if (buf != NULL)
    free(buf);

The above code for receiving only receives one single message. If you want it to match the sender which sends lots of messages, then put the receiving code in a function, and call it in a loop.

DISCLAIMER: This code is written directly in the browser, only reading the manual pages. I have not tested it.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • How can i decide messages fixed length? I want to make it dynamic. May be problem in receive.c file. can u please suggest me some sample example for this. – user1089679 Jun 25 '12 at 09:47
  • @user1089679 Edited my answer to include some code on how to handle dynamic messages. – Some programmer dude Jun 25 '12 at 10:11
  • What about this mlen in sender code i think mlen = strlen(tmp). am i right? – user1089679 Jun 25 '12 at 11:45
  • @user1089679 Ah, that should be `msgsz`. – Some programmer dude Jun 25 '12 at 11:53
  • Thanks For Your Answer. I will put this concept in my requirements and let u knw if i will face any issue. – user1089679 Jun 26 '12 at 05:51
  • What about free of realloc(). I am getting problem in example which i describe here http://stackoverflow.com/questions/11201990/error-in-realloc-or-free-in-message-queue-example – user1089679 Jun 26 '12 at 06:55
  • @user1089679 In the receiver, you free the message after the loop, and in the sender you free it right after `msgsnd` (it works as a copy is appended to the message queue.) Modified my code to include calls to `free`. – Some programmer dude Jun 26 '12 at 07:04
  • You Seen my problem which i given link in my above comment? It will be resolved if i will do this thing? – user1089679 Jun 26 '12 at 07:08
  • Thanks a lot its Resolved Please can u post your answer on my reallocate memory issue problem question which i given in above link so i can aspect both answers. – user1089679 Jun 26 '12 at 07:12
  • @user1089679 Uhm, I'm not sure about what I did to solve the other problem? :) – Some programmer dude Jun 26 '12 at 07:19
  • Can we take 2 fileds which have dynamically allocation i tried but its not working. first dynamic filed was overwrite by second one because there are only offset difference is only 1. Are u understand my problem? – user1089679 Jun 26 '12 at 08:15
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/13032/discussion-between-user1089679-and-joachim-pileborg) – user1089679 Jun 26 '12 at 08:22