Linux interprocess communication (IPC) -- message queue

Message queuing is a method of inter process communication. It has two operations: one is to send messages (that is, write data to memory), and the other is to get messages (that is, another process reads data in memory)


Let's look at the of message queue

Functions needed to create, write, read, etc

Create: msgget ((key_t)key, int msgflg)           I have written the (key_t)key in the pipeline and shared memory. There is no requirement for the key value. A 32-bit integer greater than zero is OK, and it is used to distinguish from other message queues, so the key value should not be repeated with other message queues

msgflg is a flag bit, usually IPC_CREAT :
If the message queue object does not exist, create it; otherwise, open it; A help manual is attached below

Write data (send message): int msgsnd (int msqid, struct msgbuf * msgp, int msgsz, int msgflg)

The parameter msqid is the id of the message queue created above    

struct msgbuf *msgp is the structure pointer   This structure is the message body

msgsz is the size of the message body

msgflg generally defaults to 0

Read data (read message): size_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long type,int msgflg)

smqid is the created message queue id   

struct msgbuf *msgp   Structure pointer

size_t msgsz is the size of the stored message

long type   Is the type of message

int msgflg flag bit, generally 0 by default

A help manual is attached below:

The above structure struct msgbuf is the message body. Type is used to distinguish messages. The type of message you send or get must be long

The following char array is the maximum memory used to send or get messages (it should be mentioned here that the message body size in msgsnd mentioned above only counts the char array in this structure, not dragon)

  Here's the code implementation: writing the sender

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

struct message
{
    long type;
    char buff[32];
};
 
int main()
{
    int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600 is permission
    assert(msgid != -1);

    struct message me;
    me.type = 1;  //This defines the message type as 1
    strcpy(me.buff,"hello"); //Write hello to buff

    msgsnd(msgid,(void*)&me,32,0); //Send message to message queue
 
}

Preparation of acquisition end:

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

struct message
{
    long type;
    char buff[32];
};
 
int main()
{
    int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600 is permission
    assert(msgid != -1);

    struct message me;
    msgrcv(msgid,&me,32,1,0); //The maximum number of message stores is 32. 1 is type and 0 is the default flag bit
    printf("read msg:%s \n",me.buff);
 
}

A screenshot of the operation is attached below (where xiaoxi is sending a message and haha is getting a message)   The number of bytes used should be 32     Because xiaoxi is the sender   I just ran it, so it adds up to 64

  Then ipcs -q is to check the usage of message queue. 4d2 under the key is the value of 1234 converted to hexadecimal

Then we change the message type value of the message sent from 1 to 2, and the acquisition side code remains unchanged. Let's take a look at the results again

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

struct message
{
    long type;
    char buff[32];
};
 
int main()
{
    int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600 is permission
    assert(msgid != -1);

    struct message me;
    me.type = 2;  //This defines the message type as 1
    strcpy(me.buff,"hello"); //Write hello to buff

    msgsnd(msgid,(void*)&me,32,0); //Send message to message queue
 
}

Then we will find that the data acquisition end cannot obtain the data and has been blocked in that block because of the wrong type. The writing end writes type 2 and reads type 1

  Because the type is wrong, the writing end writes type 2 and the reading end reads type 1, so it can't be read. Is there any way to make it read? The stupidest way is to change the message type of the reading end to 2, which is also the most conventional way. Let me make a very interesting method:

        Change the message type of msgrcv on the reader side to 0, that is, the default type. In this way, it will accept all data types. Let's try: only change the receiver side, the sender side code should not be, or type 2

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

struct message
{
    long type;
    char buff[32];
};
 
int main()
{
    int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600 is permission
    assert(msgid != -1);

    struct message me;
    msgrcv(msgid,&me,32,0,0); //The maximum number of message stores is 32. 1 is type and 0 is the default flag bit
    printf("read msg:%s \n",me.buff);
 
}

Attach a screenshot of the operation:

  Then delete the message queue msgctl(msgid,IPC_RMID,NULL)

Just write the code to the end of the acquisition end!

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

struct message
{
    long type;
    char buff[32];
};
 
int main()
{
    int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600 is permission
    assert(msgid != -1);

    struct message me;
    msgrcv(msgid,&me,32,0,0); //The maximum number of message stores is 32. 1 is type and 0 is the default flag bit
    printf("read msg:%s \n",me.buff);
    
    if(msgctl(msgid,IPC_RMID,NULL) == -1)   //The NULL parameter in msgctl has not been understood. Ask the teacher in the next class and fill it in the comment area
    {
        printf("delete error");
    }
 
}

In this way, the message queue can be deleted after the program execution is completed!

"Come on   Brothers   BAT   I'm coming "

Tags: Linux ipc

Posted on Sat, 20 Nov 2021 14:18:36 -0500 by tc1