Let’s talk about how to use or not use message queues for inter-process communication. Message queues have many similarities with named pipes. For more information about named pipes, please refer to my other article: Linux inter-process communication - using named pipes
1. What is a message queue
Message Queues provide a way to send a block of data from one process to another. Each data block is considered to contain a type, and the receiving process can independently receive data structures containing different types. We can avoid the synchronization and blocking problems of named pipes by sending messages. But message queues, like named pipes, have a maximum length limit for each data block.
Linux uses the macros MSGMAX and MSGMNB to limit the maximum length of a message and the maximum length of a queue.
2. Using message queue in Linux
Linux provides a series of message queue function interfaces that allow us to easily use it to achieve inter-process communication. Its usage is similar to the other two System V PIC mechanisms, namely semaphores and shared memory.
1. msgget function
This function is used to create and access a message queue. Its prototype is:
int msgget(key_t, key, int msgflg);
##With other IPC The mechanism is the same, the program must provide a key to name a specific message queue. msgflg is a permission flag, indicating the access permission of the message queue, which is the same as the access permission of the file. msgflg can be ORed with IPC_CREAT, which means to create a message queue when the message queue named by key does not exist. If the message queue named by key exists, the IPC_CREAT flag will be ignored and only an identifier will be returned.
It returns an identifier (non-zero integer) of the message queue named by key, and returns -1 on failure.
2, msgsnd function
This function is used to add messages to the message queue. Its prototype is:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid is the message queue identifier returned by the msgget function.
msg_ptr is a pointer to the message to be sent, but the data structure of the message has certain requirements. The message structure pointed to by the pointer msg_ptr must start with a long integer member variable Structure, the receiving function will use this member to determine the type of message. So the message structure should be defined like this:
struct my_message{
- ##long
int message_type;
- /* The data you wish to transfer*/ ##};
msg_sz is the length of the message pointed to by msg_ptr. Note that it is the length of the message, not the length of the entire structure. That is to say, msg_sz does not include the length of the long integer message type member variable.
msgflg is used to control what will happen when the current message queue is full or the queue message reaches the system-wide limit.
If the call is successful, a copy of the message data will be placed in the message queue and 0 will be returned. If it fails, -1 will be returned.
3. msgrcv function
This function is used to obtain messages from a message queue. Its prototype is
[cpp]
view plain copy
##msgid, msg_ptr, msg_st also function msgsnd Same as function.
msgtype can implement a simple receiving priority. If msgtype is 0, get the first message in the queue. If its value is greater than zero, the first message with the same message type will be obtained. If it is less than zero, get the first message whose type is equal to or less than the absolute value of msgtype.
msgflg is used to control what will happen when there is no message of the corresponding type in the queue to receive.
When called successfully, this function returns the number of bytes placed in the receiving buffer, the message is copied to the user-allocated buffer pointed to by msg_ptr, and then deleted from the message queue corresponding message. Returns -1 on failure.
4. msgctl function
This function is used to control the message queue. It is similar to the shmctl function of shared memory. Its prototype is:
-
int msgctl(int msgid, int command, struct msgid_ds *buf);
command is the action to be taken, it can take 3 values,
IPC_STAT: Set the data in the msgid_ds structure to the current associated value of the message queue, that is, use the current value of the message queue The associated value overrides the value of msgid_ds.
IPC_SET: If the process has sufficient permissions, set the current associated value of the message queue to the value given in the msgid_ds structure
IPC_RMID: Delete the message queue
buf is a pointer to the msgid_ds structure, which points to the message queue mode and access permissions structure. The msgid_ds structure includes at least the following members:
- struct msgid_ds
{ uid_t shm_perm.uid ; -
## uid_t shm_perm.gid;
-
mode_t shm_perm.mode;
-
};
Returns 0 on success and -1 on failure.
3. Use message queue for inter-process communication
Without stopping, after introducing the definition of the message queue and the available interfaces, let's take a look at how it allows processes to communicate. Since unrelated processes can communicate, we will write two programs here, msgreceive and msgsned, to represent receiving and sending information. Under normal circumstances, we allow both programs to create messages, but only the receiver deletes the last message after it has received it.
The program source file for receiving information is msgreceive.c and the source code is:
[cpp]
view plain copy
发送信息的程序的源文件msgsend.c的源代码为:
#include
#include
#include
#include
#include
#include
#define MAX_TEXT 512
struct msg_st
{
long int msg_type;
char text[MAX_TEXT];
};
int main()
{
int running = 1;
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
while(running)
{
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
data.msg_type = 1;
strcpy(data.text, buffer);
if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if(strncmp(buffer, "end", 3) == 0)
running = 0;
sleep(1);
}
exit(EXIT_SUCCESS);
}
运行结果如下:
4. Example Analysis - Message Type
Here we mainly explain what the message type is. Pay attention to the variable msgtype defined in the main function of the msgreceive.c file (annotated as note 1). It is used as the value of the received information type parameter of the msgrcv function, and its value is 0. , indicating getting the first available message in the queue. Let's take a look at the statement data.msg_type = 1 in the while loop in the msgsend.c file (note 2). It is used to set the information type of the information sent, that is, the type of information sent is 1. So the program msgceive can receive the information sent by the program msgsend.
What will happen if note 1, that is, the statement in the main function of the msgreceive.c file is changed from long int msgtype = 0; to long int msgtype = 2;, msgreceive will not be able to Receive information sent by the program msgsend. Because when calling the msgrcv function, if msgtype (the fourth parameter) is greater than zero, only the first message with the same message type will be obtained. After modification, the message type obtained is 2, and the message type sent by msgsend is 1. So it cannot be received by the msgreceive program. Recompile the msgreceive.c file and execute it again. The results are as follows:
We can see that msgreceive No information or output is received, and when msgsend inputs end, msgreceive does not end. Through the jobs command, we can see that it is still running in the background.
5. Comparison between message queue and named pipe
Message queue and named pipe have many similarities. Similarly, the processes communicated by the message queue can be unrelated processes, and they all transmit data through sending and receiving. In a named pipe, write is used to send data and read is used to receive data. In a message queue, msgsnd is used to send data and msgrcv is used to receive data. And they have a maximum length limit for each data.
Compared with named pipes, the advantages of message queues are that: 1. Message queues can also exist independently of the sending and receiving processes, thus eliminating the need to synchronize the opening and closing of named pipes. difficulties that may arise. 2. At the same time, by sending messages, you can also avoid the synchronization and blocking problems of named pipes, and there is no need for the process itself to provide synchronization methods. 3. The receiving program can selectively receive data through message types, instead of only receiving data by default like in named pipes.
The above is the detailed content of What is a message queue? Using message queue in Linux. For more information, please follow other related articles on the PHP Chinese website!