“This is the 15th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

The previous article introduced the creation and management of processes under Linux, and introduced the ways of inter-process communication successively: pipeline, memory mapping, shared memory and so on. This article continues with Linux’s interprocess communication mode message queues.

1. Message queue introduction

Message queue by name literally understood is queue queue – and ordinary supermarket shopping queue payment structure, message queue and FIFO is very similar, is a queue structure, can have multiple processes to write information to the queue, multiple processes from the queue to read information. But the FIFO needs to read, write both ends of the prior open, to start the information transfer work. On the other hand, message queues can write information to the queue in advance and open it to read the information as needed.

Matters needing attention:

  1. A message queue is a sequential queue structure. Each message written to the queue is appended to the queue, and each message read is removed from the queue.
  2. The write function does not block unless the queue is full of messages.
  3. The read function blocks if it cannot read data from the queue.

View all message queues in the current system:

[root@wbyq 20181005]# ipcs -q ------ Message Queues -------- The number of bytes used by Message Queues. Key msqID Owner perms used-bytes messages 0x000004d3 0 root 666 65532 192 0x00003044 32769 root 666 65424 564 0x0a120534 65538 root 0 2352 21 0x0a00000f 196611 root 0 65520 2730 0xffffffff 163844 root 0 0 0Copy the code

View message queue details:

[root@wbyq 20181005]# ipcs -l ------ Shared Memory Limits -------- max number of segments = 4096 max seg size (kbytes) =  4194303 max total shared memory (kbytes) = 1073741824 min seg size (bytes) = 1 ------ Semaphore Limits -------- max number of arrays = 128 max semaphores per array = 250 max semaphores system wide = 32000 max ops per semop call = 32 semaphore max value = 32767 ------ Messages: Limits -------- Max Queues System Wide = 1736 maximum number of message queues supported by the system Max size of message (bytes) = 65536 [Maximum number of bytes of a message] Default Max size of queue (bytes) = 65536 [Default size of a queue 65536] The default total size of a queue is 65535 bytes. The maximum number of bytes in a message queue and the maximum number of messages cannot exceed 65535 bytes.Copy the code

The System V IPC mechanism message queue-related function interface: All functions are listed here, and the usage of each function is described in detail below.

#include <sys / types.h>
#include <sys / ipc.h>
#include <sys / msg.h>
int msgget(key_t key, int msgflg);
int msgsnd(int msqid, struct msgbuf * msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, struct msgbuf * msgp, size_t msgsz, long msgtyp, int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds * buf);
Copy the code

2. Message queue related functions are introduced

2.1 msgget function

Function prototype:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
Copy the code

The msgget function is used to create and access a message queue. Parameter (1) key: Is a key that uniquely identifies a message queue. If IPC_PRIVATE(value 0, creating a message queue accessible only to the creator process) is used to create a message queue that is used only by the calling process. A key with a non-zero value (which can be obtained by the ftok function) creates a message queue that can be shared by multiple processes; (2) MSGFLG: specifies the access permission of the queue and the creation flag. The optional values of the creation flag are IPC_CREAT and IPC_EXC. If IPC_CREAT is specified separately, msgGET returns either the newly created message queue ID or the message queue ID with the same key value. If both IPC_EXCL and IPC_CREAT are specified, either a new message queue is created, or the call fails and returns -1 if the queue exists.

/ * 1. Create a message queue * / int msgid = msgget ((key_t) 1235066 6 | IPC_CREAT);Copy the code

Return value On successful execution, the message queue identity value is returned (0 is also successful).

Failure returns -1 and errno is set to one of the following values.

EACCES: the specified message queue exists, but the calling process does not have access to it and does not have CAP_IPC_OWNER rights. The message queue specified by EEXIST: key exists, and the MSGFLG specifies both IPC_CREAT and IPC_EXCL flags ENOENT: The message queue specified by key does not exist and the IPC_CREAT flag is not specified in MSGFLG. ENOMEM: A message queue needs to be established, but the memory is insufficient. ENOSPC: a message queue needs to be established, but the maximum capacity of a message queue has been reachedCopy the code

2.2 MSGSND and MSGRcy functions

Prototype:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
Copy the code

function

The MSGSND and msgrcy functions are used to add messages to and retrieve information from a message queue.

parameter

(1) msgid: specifies the ID of the message queue; Is usually the return value of success from the msgget function.

(2) MSGBUF: is the message structure, its length must be less than the upper limit specified by the system, must start with a long integer member variable, the receiving function will use this member variable to determine the type of the message. The structure must be overridden so that the first parameter type cannot be changed and the others can be customized.

As follows:

struct msgbuf {
    long mtype;         /* type of message */
    char mtext[1];       /* message text */
};
Copy the code

The field mtype is the message type specified by the user (usually any number from 1 to 5). The second member of this structure is just an illustrative structure. In fact, the user can use any type of data, namely the message content.

(3) MSGSZ is the size of the message body, the maximum size of each message body should not exceed 4K; Does not contain the four bytes occupied by the message type, the length of the mtext

(4) MsGTYP has three options:

```cpp
Copy the code

Msgtyp == 0 Receives the first message in the queue, regardless of the message type msGTYp > 0 Receives the first lowest type message whose type is less than or equal to the absolute value of MSGTYP

(5) MSGFLG has 3 options:

IPC_NOWAIT: When the message queue is full, the MSGSND function returns IPC_NOERROR without waiting: If the sent message is larger than size bytes, the message is truncated and the truncated portion is discarded without notifying the sending process.Copy the code

2.3 MSGCTL function

Prototype:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
Copy the code

function

MSGCTL is a message queue control function that is often used to delete message queues.

parameter

(1) MSqID: message queue identifier returned by MSgGET.

(2) CMD: usually IPC_RMID to delete the message queue.

(3) The parameter buf is usually NULL.

View system messages by running commands

(1) ipcs -q command to check the message queue of the system

(2) IPcs -m Displays the shared memory of the system

(3) IPCS -S check the semaphore set of the system.

3. Example code: Message queue Example 1

The following two procedures compiled separately, run in turn, regardless of order, you can see the effect.

3.1 Sending Messages

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/stat.h> #define BUFFER 255 struct msgtype { Char buf[BUFFER]; }; int main(int argc,char **argv) { if(argc! =3) {printf("./app < message > < message type - integer >\n"); return 0; } / * 1. Create a message queue * / int msgid = msgget ((key_t) 1235066 6 | IPC_CREAT); */ struct msgtype MSG; memset(&msg,0,sizeof(struct msgtype)); msg.mtype = atoi(argv[2]); // Assign strncpy(msg.buf,argv[1],BUFFER) to the members of the structure; msgsnd(msgid,&msg,sizeof(struct msgtype),0); return 0; }Copy the code

3.2 Reading Messages

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/msg.h>
#define BUFFER 255
struct msgtype {
    long mtype;
    char buf[BUFFER];
};

int main(int argc,char **argv)
{
	if(argc! =2)
	{
		printf("./app < message type - integer >\n");
		return 0;
	}
	/*1. Create a message queue - open a message queue if it exists */
    int msgid = msgget((key_t)1235.0666 | IPC_CREAT); // Get the message queue
    struct msgtype msg;
    memset(&msg,0.sizeof(struct msgtype));
    while(1)
    {
		/*2. Read the specified message type */ from the message queue
        msgrcv(msgid,&msg,sizeof(struct msgtype),atoi(argv[1]),0);
        printf("Read message: %s\n", msg.buf);
    }
    return 0;
}
Copy the code

4. Case code: Basic use of message queues

Here are two examples, one for creating a queue and writing data to the queue, and the other for reading data from the queue.

4.1 Writing a Message to a queue

Two additional parameters are passed in to run the program. One is the type of message and one is the specific content.

./app 1 hello
./app 2 123456789
Copy the code

Sample code:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>

struct msgbuf
{
    long mtype;       /* message type, must be > 0 */
    char mtext[1024];    /* message data */
};

int main(int argc,char **argv)
{
    if(argc! =3)
    {
        printf("./app < message type > < message content >\n");
        return 0;
    }
    /*1. Create message queue */
    int msqid=msgget(123456.0666|IPC_CREAT);
    /*2. Add data to message queue */
    struct msgbuf msg_buf;
    msg_buf.mtype=atoi(argv[1]); // Message types 1, 2, 3, 4, 5
    strcpy(msg_buf.mtext,argv[2]); // Message content
    msgsnd(msqid,&msg_buf,sizeof(struct msgbuf),0);
    printf("Message sent successfully :%s,%s\n",argv[1],argv[2]);
    return 0;
}
Copy the code

4.2 Reading messages from the queue

#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/wait.h> #include <sys/shm.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1024]; /* message data */ }; int main(int argc,char **argv) { if(argc! Printf ("./app < message type >\n"); return 0; } / * 1. Create a message queue * / int msqid = msgget (123456066 6 | IPC_CREAT); */ struct msgbuf msg_buf; msgrcv(msqid,&msg_buf,sizeof(struct msgbuf),atoi(argv[1]),0); Printf (" Message read successfully :%d,%s\n",msg_buf.mtype,msg_buf.mtext); return 0; }Copy the code