[Linux]-Message Queue for IPC Process Communication

System V message queue

Message queue is a simple and effective way to transfer binary data between two processes. Each data block has a specific type, and the receiver can receive data effectively according to the type, instead of having to receive data in a first-in-first-out manner, as pipes and named pipes do.

The type of data block is actually defined by itself. The type here does not mean int, long, but a positive integer. The author interprets the type here as a logo, and we can use the following figure to explain it to you.


Unlike pipelines, message queues are message-based, whereas pipelines are byte stream-based, and message queues are not necessarily read first in first out. There is a common disadvantage between message queues and named pipelines, that is, the maximum length of each message is limited, and the lifecycle of message queues is accompanied by the kernel.

The message queue maintained in the kernel is actually a linked list, so let's look at how the message queue in the kernel is managed.

Message queue kernel management

struct msqid_ds
{
    struct ipc_perm msg_perm;//Message queue operation privilege information
    struct msg *msg_first; //The first information pointer on the message queue
    struct msg *msg_last;//The last information pointer on the message queue
    __kernel_time_t msg_stime;//The last time msgsnd was called
    __kernel_time_t msg_rtime;//The last time to call msgrcv
    __kernel_time_t msg_ctime;//Time of last modification
    unsigned long  msg_lcbytes;
    unsigned long  msg_lqbytes;
    unsigned short msg_cbytes;
    unsigned short msg_qnum;//Number of messages already in the message queue
    unsigned short msg_qbytes;//Maximum number of bytes allowed for message queue
    __kernel_ipc_pid_t msg_lspid;//The last call to the process pid of msgsnd
    __kernel_ipc_pid_t msg_lrpid;//The last call to the process pid of msgrcv
};

Here its structure has explained its chain queue, msg_first and msg_last are its head and tail pointers.

Message Queuing System Call

msgget function: create a new message queue, or get an existing message queue

int msgget(key_t key,int msgflg);

Introduction of parameters:

  • key: Used to identify the only message queue in the system, retrieved using the ftok function
  • msgflg: Often using IPC_CREAT and IPC_EXCL options, they use "|" connections directly, or | permissions on semaphores (octal)

When the function call is successful, we create a msqid_ds signal set for us in the system and initialize some parts of it. The return value of the function returns an identifier for this message queue and - 1 if it fails. In fact, we found that the system calls of the inter-process communication mechanism in the System V version are quite similar, so it is not difficult to understand the others by remembering the usage of one.

msgsnd function: sending data to message queue

int msgsnd(int msqid,const void* msg_ptr,size_t msg_sz,int msgflg);

Introduction of parameters:

  • msqid: Fill in the return value of the msgget function
  • msg_ptr: Points to a message ready to be sent, which should be defined as the following structure
struct msgbuf
{
	long mtype; //More than 0	
	char mtext[512];// Message size
};

Here, mtype is the identification of different data. It needs to fill in a data larger than 0. The message you want to send is stored in mtext.

  • The size of msg_sz: mtext message
  • msgflg: Controls the behavior of msgsnd, filling in 0 means blocking sending, and IPC_NOWAIT means non-blocking sending. If the message queue is deleted, EIDRM error return will be received, or EINTR will be received by signal interruption when the message queue is blocked.

msgrcv function: receive data from message queue

ssize_t msgrcv(int msqid,void *msg_ptr,size_t msg_sz,long mtype,int msgflg);

Introduction of parameters:

The parameters here are all the same except for mtype. Here we focus on mtype.

  • mtype: Indicates what type of data you want to pull out of the message queue. There are three cases in which the parameter is greater than zero, equal to zero and less than zero, respectively. When mtpye is greater than 0, it indicates that it wants to receive data of the same type as mtpye. The first message in the message queue is read at zero. The first type of message in the message queue is read when it is less than zero, which is smaller than the absolute value of mtpye.
  • msgflg: Set to IPC_NOWAIT to indicate that if no message in the message queue returns immediately. Setting IPC_EXCEPT and mtype greater than zero receives non-mtype data

msgmctl function: This function is used to directly control message queue information

int msgctl(int msgqid,int cmd,struct msqid_ds *buf);

The use of semaphore shared memory is basically the same as before. Here we list only three CMDS that are commonly used:

command describe
IPC_STAT This command is used to retrieve the msqid_ds data structure corresponding to the message queue and save it to the address space specified by buf
IPC_SET This command is used to set the properties of the message queue, and the properties to be set are stored in buf.
IPC_RMID Delete message queues identified by msqid from the kernel

Simple example of message queue usage

#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <string>
using namespace std;
#define TYPE 1 //The message we want to receive is defined as type 1

//The struct msgbuf // system has been defined for us
//{
//    long mtype;
//    char mtext[512];
//};

int main()
{
    int k = ftok("/tmp", 0x6666);
    int msgid = msgget(k, IPC_CREAT|0644);
    pid_t id = fork();
    if(id < 0){
        cout << "fork error !" <<endl;
    }
    if(id == 0){
        struct msgbuf _mb;
        _mb.mtype = TYPE;
        string msg = "hello msgqueue!";
        strcpy(_mb.mtext, msg.c_str());
        if(msgsnd(msgid, (void*)&_mb, sizeof(_mb.mtext), 0) < 0){
            cout << "msgsnd error !!" <<endl;
        }
    }
    else{
        struct msgbuf _mb;
        if (msgrcv(msgid, &_mb, sizeof(_mb.mtext), TYPE, 0)< 0){
            cout << "msgrcv error !!" <<endl;
        }
        char buf[100];
        strcpy(buf,_mb.mtext);
        cout << "father recv:" << buf <<endl;
    }
    waitpid(id,NULL,0);
    msgctl(msgid, IPC_RMID, NULL);
    return 0;
}

Supplementary Shell command on System V IPC

Use ipcs to view message queues, shared memory, semaphores in the system

If you want to query a single query, you can use the option, - m for shared memory, - q for message queues, and - s for semaphores. When we need to manually delete a communication mechanism, we use ipcrm [option] [shmid].

Keywords: less shell

Added by NathanS on Wed, 28 Aug 2019 09:52:44 +0300