1

how do you get the message from the message queue in get.c file, after sending message and process id from send.c?

from send.c:

 #include <sys/types.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

 #define   MAX_COUNT  200
 #define   BUF_SIZE   100
 #define MSGSZ     255
 #define KEY 10
  //from http://www.tldp.org/LDP/LG/issue89/misc/raghu/send.c.txt
  /*
   * Declare the message structure.
   */
    typedef struct msgbuf {
     long    mtype;
     char    mtext[MSGSZ + 1];
     } message_buf; 

     static message_buf sbuf;
      static size_t buf_length;
     static int mqid;  

      int main(int argc, char*argv[])
      {
      pid_t  pid;
      int    i;
      char   buf[BUF_SIZE];

    if ((pid = getpid()) < 0) { //getting child process id
     perror("unable to get pid \n");
     } 
      else {
    printf("The process id is %d \n", pid);
    }

       char line[256];
      int c = 0;  //for character count 

     printf("enter word/s (must be less than or equal 256 characters): \n");
     fgets(line, 256, stdin);

     printf("\n");
     if ( c > 256 )
     {
     printf("Must enter less than or equal to 256 characters.");
     printf("Has %d characters", countChar(line)); 
      exit(0);
      }

      (void) strcpy(sbuf.mtext, line);
       buf_length = strlen(sbuf.mtext) + 1;

        sbuf.mtype = pid; 
        logMessage(sbuf.mtype, line);     
     }

     int countChar(char *s) 
     { 
     int len = 0; 
     for(; *s != '\0'; s++, len++); 
       return len; 
      }

     int logMessage(int serviceId,char*message)
    {
    int rv, mask, msgid;  
    key_t key = KEY;
    mask = 0644|IPC_CREAT;
    msgid = msgget(key, mask);

if (msgsnd(msgid, &sbuf, buf_length, IPC_NOWAIT) < 0) //sending message
{
 perror("msgsnd");
 exit(1);
 }
 else
 {
 printf("id - %d : message - %s \n", serviceId, message);
 }

return rv;
  }

from get.c:

  #include <stdio.h>
  #include <stdlib.h>
  #include <signal.h>
  #include <sys/msg.h>
  #include <sys/ipc.h> 
  #include <stdarg.h>
  #include <sys/types.h>
  #include <unistd.h>
  #include <errno.h>
  #include <string.h>
  #define MSGSZ    255
  #define MSGCHARS     255
  #define KEY 10

 typedef struct msgbuf
 {
int mtype;
char mtext[MSGSZ]; 
}message_buf;

static int queue_id;
void     INThandler(int);

 int main(int argc, char*argv[])
{
 key_t key = KEY
message_buf  rbuf;
 int msgflg = 0644;
int msqid = msgget(key, msgflg);

if (msqid < 0) {
    perror("msgget");
    exit(1);
}    
  rbuf.mtype = 1;
  for(;;){
 if (msgrcv(msqid, &rbuf, MSGSZ, 1, 0) < 0) {
    perror("msgrcv");
    exit(1);
   }
   printf("id - %d : message - %s ", rbuf.mtype, rbuf.mtext);
   } 

     signal(SIGINT, INThandler);//the function starts with ctrl+c. 
     while (1)
      pause();

return 0;
}

  void  INThandler(int sig)//this function  deletes the message queue
  {
 signal(sig, SIG_IGN);
 int mask, msgid;
 key_t key = KEY;
mask = 0644;
msgid = msgget(key, mask);  

if (msgid == -1) {
    printf("Message queue does not exist.\n");
    exit(EXIT_SUCCESS);
}

if (msgctl(msgid, IPC_RMID, NULL) == -1) {
    fprintf(stderr, "Message queue could not be deleted.\n");
    exit(EXIT_FAILURE);
}
    else {
printf("Message queue was deleted.\n");
    }
    exit(0);
return EXIT_SUCCESS;  
}

I was able to send the process id and message successfully from send.c, but when executing get.c the code returns nothing. How do you fix that?

user4728257
  • 25
  • 10

1 Answers1

2

Your problem is identified by the POSIX specification for msgrcv(). The msgtyp argument is the fourth argument, specified as 1 in your code:

The argument msgtyp specifies the type of message requested as follows:

  • If msgtyp is 0, the first message on the queue shall be received.

  • If msgtyp is greater than 0, the first message of type msgtyp shall be received.

  • If msgtyp is less than 0, the first message of the lowest type that is less than or equal to the absolute value of msgtyp shall be received.

Since the sending process is not the init process, there never will be a message from PID = 1. Simply changing your call from:

if (msgrcv(msqid, &rbuf, MSGSZ, 1, 0) < 0)

to

if (msgrcv(msqid, &rbuf, MSGSZ, 0, 0) < 0)

meant that the next run of the receiver got:

Waiting...
id - 60464 : message -  Waiting...
id - 60478 : message -  Waiting...
id - 60482 : message -  Waiting...
id - 71796 : message -  Waiting...

where the Waiting... was printed in a printf() statement inside the loop before the if statement. This shows that the messages from the previous abortive attempts to read a message were waiting to be read.

The message comes back as zero length because you haven't been careful enough in defining your message structures. In particular, the receiving message structure uses int rather than long as required by the specification, so on my machine where sizeof(int) == 4 and sizeof(long) == 8 and the values are little-endian, the string in the receiver is misplaced relative to the string in the sender, and 0 bytes are placed. Fix that up and the message is transmitted.

Note that the interrupt handler is not set early enough; it is never actually used in the original code.

Lessons:

  1. Read the specification carefully.
  2. Use consistent structure definitions (create a header used by both sender and receiver).
  3. Position signal handling code properly.
  4. Read up on How to avoid using printf() in a signal handler. It is going to be fairly safe here, but it is technically undefined behaviour, and that should be avoided.

Code: send.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>

#define MSGSZ   255
#define KEY     10

typedef struct msgbuf
{
    long mtype;
    char mtext[MSGSZ+1];
} message_buf;

int main(void)
{
    message_buf sbuf;
    sbuf.mtype = getpid();

    printf("The process id is %ld\n", sbuf.mtype);

    printf("enter word/s (must be less than %d characters):\n", MSGSZ+1);
    if (fgets(sbuf.mtext, sizeof(sbuf.mtext), stdin) == 0)
    {
        printf("EOF detected\n");
        exit(EXIT_FAILURE);
    }

    printf("\n");

    key_t key = KEY;
    int mask = 0644 | IPC_CREAT;
    int msgid = msgget(key, mask);
    if (msgid < 0)
    {
        fprintf(stderr, "Failed to create msg key %d\n", key);
        exit(EXIT_FAILURE);
    }

    if (msgsnd(msgid, &sbuf, strlen(sbuf.mtext)+1, IPC_NOWAIT) < 0)
    {
        perror("msgsnd");
        exit(EXIT_FAILURE);
    }

    printf("id - %ld : message - %s\n", sbuf.mtype, sbuf.mtext);

    return 0;
}

Code: recv.c

#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>

#define MSGSZ    255
#define KEY 10

typedef struct msgbuf
{
    long mtype;
    char mtext[MSGSZ+1];
} message_buf;

static void INThandler(int);

int main(void)
{
    key_t key = KEY;
    int msgflg = 0644;
    message_buf rbuf;

    int msqid = msgget(key, msgflg);

    if (msqid < 0)
    {
        perror("msgget");
        exit(1);
    }

    signal(SIGINT, INThandler);

    rbuf.mtype = 1;
    for ( ; ; )
    {
        printf("Waiting...\n");
        ssize_t nbytes = msgrcv(msqid, &rbuf, MSGSZ, 0, 0);
        if (nbytes < 0)
        {
            perror("msgrcv");
            exit(1);
        }
        printf("id - %ld : message (%d) - %s", rbuf.mtype, (int)nbytes, rbuf.mtext);
    }

    return 0;
}

static void  INThandler(int sig)
{
    signal(sig, SIG_IGN);
    int mask, msgid;
    key_t key = KEY;
    mask = 0644;
    msgid = msgget(key, mask);

    if (msgid == -1)
    {
        printf("Message queue does not exist.\n");
        exit(EXIT_SUCCESS);
    }

    if (msgctl(msgid, IPC_RMID, NULL) == -1)
    {
        fprintf(stderr, "Message queue could not be deleted.\n");
        exit(EXIT_FAILURE);
    }
    else
        printf("Message queue was deleted.\n");
    exit(0);
}

Sample run

$ ./send <<< "The message to be sent."
The process id is 71901
enter word/s (must be less than 256 characters):

id - 71901 : message - The message to be sent.

$ ./send <<< "Another message to be sent."
The process id is 71902
enter word/s (must be less than 256 characters):

id - 71902 : message - Another message to be sent.

$ ./send <<< "A third message sent to the receiver."
The process id is 71903
enter word/s (must be less than 256 characters):

id - 71903 : message - A third message sent to the receiver.

$ ./recv
Waiting...
id - 71901 : message (25) - The message to be sent.
Waiting...
id - 71902 : message (29) - Another message to be sent.
Waiting...
id - 71903 : message (39) - A third message sent to the receiver.
Waiting...
^CMessage queue was deleted.
$
Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278