Linux Interprocess Communication-Message Queuing

Posted by Pottsy on Sat, 10 Aug 2019 15:57:00 +0200

concept

What is a message queue?

  • Message queues are also called message queues, or mailboxes. It is a communication mechanism of Linux. The data transmitted by this communication mechanism has a certain structure, not a simple byte stream.
  • The essence of message queue is actually a linked list provided by the kernel, which implements a data structure based on the linked list.
  • Writing data to a message queue is actually inserting a new node into the data structure; summarizing and reading data from the message queue is actually removing a node from the data structure.
  • Message queuing provides a way to send a piece of data from one process to another.
  • Message queues have the same drawbacks as pipelines, that is, the maximum length of each data block is upper bound, and the maximum total length of all queues on the system is also upper bound.

Queue working mechanism

User Message Buffer

Both sending and receiving processes need to use message buffers to temporarily store messages in the process space. The structure of the message buffer is defined as follows

struct msgbuf {
	long mtype;         /* Type of message */
	char mtext[1];      /* Message body */
};
  • Data types can be distinguished by mtype, and mtype can also be judged whether it is the data to be received or not.
  • mtext [] is an array that stores the message body, and the length of the array can be defined according to the size of the message.

Create message queues

Creating message queues through msgget
The prototype of the function is as follows

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

Parameters:

  • key: The name of a message queue
  • msgflg: consists of nine permission flags, which are the same as the mode l pattern flag used when creating files. Here are two examples
IPC_CREAT
	If the message queue object does not exist, it is created, otherwise the open operation is performed.
IPC_EXCL
	If the message object does not exist, it is created, otherwise an error is generated and returned

Return value:

  • Successful msgget returns a non-negative integer, the identity code of the message queue.
  • Failure returns "-1"

So how do I get the key value?

  • Define key values through macros
  • To generate key value by ftok function, we will not introduce the usage of ftok function in detail.

Add information to message queue

Add data to the message queue using the msgsnd() function
The prototype of the function is as follows

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

Parameters:

  • msgid: Message queue identifier returned by msgget function
  • msg_ptr: is a pointer to the message to be sent.
  • msg_sz: The length of the message to which msg_ptr points, the size of the mtext in the message buffer structure, excluding the type of data
  • msgflg: Controls what happens when the current message queue is full or reaches the system ceiling
    Such as:
    msgflg = IPC_NOWAIT indicates that the queue is full and waiting, returning an EAGAIN error

Return value:

  • Successful return to 0
  • Failure returns - 1

Reading Cancels from Message Queues

To read and cancel messages from message queues, we use the msgrcv() function.
The prototype of the function is as follows

int  msgrcv(int msgid, void *msg_ptr, size_t msgsz,
		 long int msgtype, int msgflg);

Parameters:

  • msgid: Message queue identifier returned by msgget function
  • msg_ptr: A pointer to the message to be received.
  • msgsz: The length of the message that msg_ptr points to, the size of mtext in the message buffer structure, excluding the type of data
  • msgtype: A simple form of receiving priority
    msgtype=0 returns the first message of the queue
    Msgtype > 0 returns messages of the first type of queue equal to msgtype
    Msgtype < 0 returns a message whose first type of queue is less than or equal to the absolute value of msgtype
  • msgflg: Controls what happens when there is no corresponding type of message in the queue to receive
    msgflg=IPC_NOWAIT, the queue has no readable message and does not wait, returns ENOMSG error.
    msgflg=MSG_NOERROR, truncated when message size exceeds msgsz
Be careful

Msgtype > 0 and msgflg=MSC_EXCEPT, receiving type is not equal to msgtype's first message

Return value:

  • Successfully returning the number of characters actually placed in the receiving buffer
  • Fail, return - 1

Control function of message queue

Function prototype

int  msgctl(int msqid, int command, strcut msqid_ds *buf);

Parameters:

  • msqid: Message queue identifier returned by msgget function
  • command: The action to be taken (with three values available) is as follows

    Note: If you choose to delete the queue, the third parameter passes NULL
    Return value:
    If the operation succeeds, return 0; if it fails, return -1.

View message queues

  • View message queues
    The ipcs-q command looks at the message queue that has been created, including its key value information, id information, owner information, file permission information, number of bytes used, and number of message bars.
  • Ipcrm-Q plus the key value of the message queue, or to delete a message queue.

For example, a parent process writes a message (first the data type sent, then the data) and a child process receives a message of type 1.

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

#define MSGKEY 123

//The data structure of a message is a structure that starts with a long integer member variable.
struct msgstru
{
	long msgtype;
	char msgtext[2048];
};

int main()
{
	struct msgstru msgs;
	char str[256];
	int msg_type;
	int ret_value;
	int msqid;
	int pid;

	//Check if the message queue exists
	msqid = msgget(MSGKEY, IPC_EXCL);//(Key name, permission)
	if (msqid < 0)
	{
		//Create message queues
		msqid = msgget(MSGKEY, IPC_CREAT | 0666);
		if (msqid <0)
		{
			printf("failed to create msq | errno=%d [%s]\n", errno, strerror(errno));
			exit(-1);
		}
	}

	pid = fork();//Create subprocesses
	if (pid > 0)
	{
		//Paternal process
		while (1)
		{
			printf("input message type:\n");//Input message type
			scanf("%d", &msg_type);
			if (msg_type == 0)
				break;

			printf("input message to be sent:\n");//Input message information
			scanf("%s", str);

			msgs.msgtype = msg_type;
			strcpy(msgs.msgtext, str);

			//Send message queues (sizeof message length, not the entire structure length)
			ret_value = msgsnd(msqid, &msgs, sizeof(msgs.msgtext), IPC_NOWAIT);
			if (ret_value < 0)
			{
				printf("msgsnd() write msg failed,errno=%d[%s]\n", errno, strerror(errno));
				exit(-1);
			}
		}
	}
	else if (pid == 0)
	{
		//Subprocesses
		while (1)
		{
			msg_type = 1;//The received message type is 1
			msgs.msgtype = msg_type;

			//Send message queues (sizeof message length, not the entire structure length)
			ret_value = msgrcv(msqid, &msgs, sizeof(msgs.msgtext), msgs.msgtype, IPC_NOWAIT);
			if (ret_value > 0)
			{
				printf("read msg:%s\n", msgs.msgtext);
			}
		}
	}
	else
	{
		printf("fork error\n");
		//Delete message queue
		msgctl(msqid, IPC_RMID, 0);
		exit(1);
	}

	return 0;
}

Operation results

Topics: Linux less