Click here to read the original
Another collection Ljianhui's Column beginner Linux
Here's how to use Message Queuing for interprocess communication, where Message Queuing has a lot in common with named pipes. More about Named pipes can be found in one of my other articles: Linux interprocess communication-using named Pipes one, what is Message Queuing Message Queuing provides a way to send a block of data from one process to another. Each block of data is considered to contain a type, and the receiving process can independently receive data structures that contain different types. We can avoid the synchronization and blocking problems of named pipes by sending messages. But Message Queuing, like named Pipes, has a maximum length limit for each block of data. Linux uses macro Msgmax and MSGMNB to limit the maximum length of a message and the maximum length of a queue. Second, using Message Queuing Linux in Linux provides a series of function interfaces for Message Queuing to allow us to easily use it for interprocess communication. Its usage is similar to the other two system V pic mechanisms, i.e. semaphores and shared memory. 1. Msgget function This function is used to create and access a message queue. Its prototype is:
[CPP]View PlainCopy print?
- int Msgget (key_t key, int msgflg);
Like other IPC mechanisms, a program must provide a key to name a particular message queue. MSGFLG is a permission flag that represents the access rights for Message Queuing, which is the same as file access. MSGFLG can be done or manipulated with ipc_creat, which means that when a message queue named by key is not present, a message queue is created, and if a message queue named by key is present, the IPC_CREAT flag is ignored and only one identifier is returned. It returns an identifier for a message queue named key (nonzero integer), which returns 1 on failure. 2. msgsnd function This function is used to add messages to the message queue. Its prototype is:
[CPP]View PlainCopyprint?
- 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 prepare to send a message, but the data structure of the message has certain requirements, the pointer msg_ptr the message structure must be a long integer member variable start structure, the receive function will use this member to determine the type of message. So the message structure should be defined like this:
[CPP]View PlainCopyprint?
- struct my_message{
- long int message_type;
- / * The data wish to transfer*/
- };
MSG_SZ is the length of the message that the MSG_PTR points to, note the length of the message, not the length of the entire struct, that is, the length of the member variable that MSG_SZ does not include the long integer message type. The 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 succeeds, a single copy of the message data is placed in the message queue and returns 0, returning 1 on failure. 3, MSGRCV function This function is used to get the message from a message queue, its prototype is
[CPP]View PlainCopyprint?
- int MSGRCV (int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
MsgId, Msg_ptr, Msg_st functions as function msgsnd functions. The Msgtype can implement a simple receive priority. If Msgtype is 0, it gets the first message in the queue. If its value is greater than 0, it gets the first information with the same message type. If it is less than 0, it gets the first message with a type equal to or less than the absolute value of Msgtype. The MSGFLG is used to control what happens when there are no corresponding types of messages in the queue that can be received. When the call succeeds, the function returns the number of bytes placed in the receive buffer, the message is copied to the user-allocated buffer that is pointed to by msg_ptr, and the corresponding message in the message queue is deleted. Returns-1 on failure. 4. Msgctl function This function is used to control Message Queuing, which is similar to the SHMCTL function of shared memory, and its prototype is:
[CPP]View PlainCopy print?
- int msgctl (int msgid, int command, struct msgid_ds *buf);
command is the action to be taken, which can fetch 3 values, Ipc_stat: Sets the data in the MSGID_DS structure to the current associated value of the message queue, that is, the value of Msgid_ds is overwritten with the current association value of the message queue. Ipc_set: If the process has sufficient permissions, set the current association value for the message queue to the value given in the MSGID_DS structure ipc_rmid: Delete Message Queuing buf is a pointer to the MSGID_DS structure, which points to the Message Queuing pattern and the structure of the access permission. The MSGID_DS structure includes at least the following members:
[CPP]View PlainCopyprint?
- struct MSGID_DS
- {
- uid_t Shm_perm.uid;
- uid_t Shm_perm.gid;
- mode_t Shm_perm.mode;
- };
Returns 0 on success, 1 on failure. Third, using Message Queuing for interprocess communication, after describing the definition of Message queuing and the interfaces that can be used, let's look at how it makes the process communicate. Since it is possible to allow unrelated processes to communicate with each other, we will write two programs here, Msgreceive and msgsned, to represent the receiving and sending of information. According to normal circumstances, we allow two programs to create a message, but only if the recipient finishes receiving the last message, it deletes it. The source code for the program source file that receives the information is msgreceive.c:
[CPP]View PlainCopyprint?
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/msg.h>
- struct MSG_ST
- {
- long int msg_type;
- Char Text[bufsiz];
- };
- int main ()
- {
- int running = 1;
- int msgid =-1;
- struct MSG_ST data;
- long int msgtype = 0; //NOTE 1
- //Establish Message Queuing
- MsgId = Msgget ((key_t) 1234, 0666 | Ipc_creat);
- if (MsgId = =-1)
- {
- fprintf (stderr, "Msgget failed with Error:%d\n", errno);
- Exit (Exit_failure);
- }
- //Get the message from the queue until the end message is encountered
- While (running)
- {
- if (MSGRCV (MsgId, (void*) &data, Bufsiz, msgtype, 0) = =-1)
- {
- fprintf (stderr, "MSGRCV failed with errno:%d\n", errno);
- Exit (Exit_failure);
- }
- printf ("you wrote:%s\n", Data.text);
- //Encounter End ends
- if (strncmp (Data.text, "End", 3) = = 0)
- running = 0;
- }
- //Delete Message Queuing
- if (Msgctl (MsgId, ipc_rmid, 0) = =-1)
- {
- fprintf (stderr, "Msgctl (ipc_rmid) failed\n");
- Exit (Exit_failure);
- }
- Exit (exit_success);
- }
The source code for the program that sent the message MSGSEND.C is:
[CPP]View PlainCopyprint?
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/msg.h>
- #include <errno.h>
- #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;
- //Establish Message Queuing
- MsgId = Msgget ((key_t) 1234, 0666 | Ipc_creat);
- if (MsgId = =-1)
- {
- fprintf (stderr, "Msgget failed with Error:%d\n", errno);
- Exit (Exit_failure);
- }
- //write message to message queue until end is written
- While (running)
- {
- //input data
- printf ("Enter some text:");
- Fgets (buffer, bufsiz, stdin);
- Data.msg_type = 1; //NOTE 2
- strcpy (data.text, buffer);
- //Send data to queue
- if (msgsnd (MsgId, (void*) &data, max_text, 0) = =-1)
- {
- fprintf (stderr, "msgsnd failed\n");
- Exit (Exit_failure);
- }
- //input end end input
- if (strncmp (buffer, "End", 3) = = 0)
- running = 0;
- Sleep (1);
- }
- Exit (exit_success);
- }
The results of the operation are as follows: Four, example analysis--message type Here is the main explanation of what the message type is, Note the variable msgtype (note 1), defined in the main function of the msgreceive.c file, acts as the value of the receive information type parameter of the MSGRCV function with a value of 0, which indicates that the first available message in the queue is obtained. Look again at the statement in the while loop in the msgsend.c file Data.msg_type = 1 (note 2), which is used to set the type of information that is sent, that is, the type of information it sends is 1. So the program msgreceive can receive the information sent by the program Msgsend. If you take note 1, that is, the statement in the main function of the msgreceive.c file is represented by a long int msgtype = 0; change to a long int msgtype = 2; what happens, Msgreceive will not be able to receive information sent by the program Msgsend. Because when the MSGRCV function is called, if Msgtype (the fourth argument) is greater than 0, only the first message with the same message type is obtained, the modified message type is 2, and Msgsend sends a message type of 1, so it cannot be received by the Msgreceive program. Recompile the msgreceive.c file and execute it again, the result is as follows: we can see that msgreceive has not received the information and output, and when msgsend input end, msgreceive is not finished, With the jobs command we can see that it's still running in the background. comparison between Message Queuing and named pipes Message Queuing has a lot in common with named Pipes, and as with named Pipes, the process by which Message Queuing communicates can be unrelated processes, and they all pass data in a way that is sent and received. In a named pipe, send data with write, receive data with read, then in message queue, send data with MSGSND, receive data with MSGRCV. And they have a maximum length limit for each data. The advantage of Message Queuing over named Pipes is that 1, Message Queuing can also exist independently of the send and receive processes, eliminating the difficulties that can arise when synchronizing named Pipes for opening and closing. 2. By sending messages, you can also avoid the synchronization and blocking problems of named pipes, and do not need to provide synchronization methods by the process itself. 3. The receiving program can selectively receive data through the message type, instead of being received only by default, as in a named pipe.
[Go]linux interprocess communication-use Message Queuing