1. PrefaceAll examples of this post are based on the RHEL6.5 platform (Linux kernal:2.6.32-431.el6.i686).
2. IntroductionMessage Queuing is the FIFO first principle.
A message queue is a linked list of messages. You can think of a message as a record, with a specific format and a specific priority. A process that has write permission to a message queue can add new messages to it by a certain rule, and a process that has read access to a message queue can read messages from the message queue. Message Queuing is persistent with the kernel.
There are currently two main types of Message Queuing: POSIX Message Queuing and System V Message Queuing, which are currently heavily used by System V Message Queuing. Considering the portability of the program, the newly developed application should use POSIX Message Queuing as much as possible.
Message Queuing differs greatly from the previously discussed pipeline (point this link) and FIFO (point this link), with the following two points:
·before a process writes a message to a message queue, it does not require a process to wait for the message to arrive on that queue, and the pipeline andFIFOon the contrary, when a process writes a message to it, the pipeline andFIFOmust already be open to read, otherwise the write process will block (by default).
·IPCthe persistence of the different. Pipelines andFIFOis awith Processcontinuity, when piping andFIFOwhen the last shutdown occurs, it is still in the pipeline andFIFOdata in the database will be discarded. Message Queuing iswith the kernelpersistence, when a process writes a message to a message queue and then terminates, another process can open the queue at a later time to read the message. Message Queuing is not deleted as long as the kernel is not re-bootstrap.
Each message in a message queue typically has the following properties:
· An integer representing the priority;
· The length of the data portion of the message;
· The message data itself;
One possible design for POSIX Message Queuing is a list of messages as shown in the list header, which has Message Queuing property information.
3. Create and close
POSIX Message Queuing is created, closed, and deleted using the following three function interfaces:
#include <mqueue.h> mqd_t mq_open (const char *name, int oflag,/* mode_t mode, struct mq_attr *attr */); Successfully returned message queue descriptor, failed to return-1 mqd_t mq_close (mqd_t mqdes); mqd_t mq_unlink (const char *name); Successful return 0, failure return-1
Mq_open is used to open or create a message queue.
name: Represents the name of the message queue, which conforms to thePOSIX IPCrule of name.
Oflag: Indicates the way to open, andOpenfunction is similar. There are the necessary options:o_rdonly,o_wronly,O_rdwr, there are optional options:O_nonblock,o_creat,o_excl.
Mode: is an optional parameter, inOflagcontained ino_creatflag and Message Queuing does not exist, you need to supply this parameter. Represents the default access rights. can refer toOpen.
attr: Also an optional parameter, inOflagcontained ino_creatflag and Message Queuing does not exist. This parameter is used to set some properties for the new queue, and if it is a null pointer, the default property is used.
Mq_openThe return value ismqd_tthe value of the type, called the message queue descriptor. In theLinux2.6.32The definition of this type is integer:#include <bits/mqueue.h> typedef int mqd_t;
Mq_close is used to close a message queue, similar to close to a file, and is not removed from the system after it is closed. The end of a process is automatically called to close the open message queue.
Mq_unlink is used to delete a message queue. After a message queue is created, it can be deleted only by calling the function or by the kernel bootstrap. Each message queue has a reference counter that holds the number of descriptors currently open, like a file, so this function can implement a mechanism similar to the unlink function to delete a file.
The name of the POSIX message queue creates a real pathname and a specific system implementation, and the naming rules for the specific POSIX IPC can refer to the P14 of the UNIX Network programming Volume 2: interprocess communication.
After testing, in Linux 2.6.32, the POSIX message queue created does not create a true pathname in the file system. And the POSIX name can only start with a '/', and the name cannot contain other '/'.
4. Message Queuing Properties
The POSIX standard specifies that the Message Queuing attribute mq_attr must contain the following four items:
Long mq_flags//Message Queue flag: 0 or O_nonblock, used to indicate whether blocking
The maximum number of messages for a long mq_maxmsg//Message Queue
The maximum number of bytes per message in a long mq_msgsize//Message Queue
Long MQ_CURMSGS//Message Queue current number of messages
The MQ_ATTR structure in Linux 2.6.32 is defined as follows:
#include <bits/mqueue.h>struct mq_attr { long mq_flags; /* Message Queue Flags */ long mq_maxmsg; /* Maximum number of messages */ long mq_msgsize; /* Maximum message size */ long mq_curmsgs; /* Number of messages currently queued */ long __reserved[4]; /* Ignored for input, zeroed for output */};
The properties of POSIX Message Queuing can be set and obtained through the following two functions:
#include <mqueue.h> //successfully returned 0, failed to return -1mqd_t mq_getattr (mqd_t mqdes, struct mq_attr *attr); mqd_t mq_setattr (mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);
The mq_getattr is used to get the properties of the current message queue, and mq_setattr is used to set the properties of the current message queue. The oldattr in mq_setattr is used to save the properties of the pre-modified message queue, which can be empty.
Mq_setattr can set the properties of only mq_flags, which sets or clears the non-blocking flag for Message Queuing. Other properties of the NEWATTR structure are ignored. The Mq_maxmsg and Mq_msgsize properties can only be used when creating message queues
Mq_open to set. Mq_open only sets the two properties, ignoring the other two properties. The Mq_curmsgs property can only be obtained and cannot be set.
Here is the test code:
#include <iostream> #include <cstring> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <mqueue.h> int main () {mqd_t mqid;mqid = Mq_open ("/shltsh_queue ", O_RDWR | O_creat, 0666, NULL); if (Mqid < 0) {std::cout << "open message Queue error ..." << strerror (errno) << s td::endl;return-1;} Mq_attr mqattr;if (mq_getattr (mqid, &mqattr) < 0) {std::cout << "get the Message Queue attribute error" <&L T std::endl;return-1;} Std::cout << "mq_flags:" << mqattr.mq_flags << std::endl;std::cout << "mq_maxmsg:" << Mqattr.mq_maxmsg << std::endl;std::cout << "mq_msgsize:" << mqattr.mq_msgsize << std::endl;std :: cout << "mq_curmsgs:" << mqattr.mq_curmsgs << Std::endl;}
Compile:
[Email protected] csdnblog]# g++ PIPE.CPP-LRT
Output:
mq_flags:0
Mq_maxmsg:10
mq_msgsize:8192
mq_curmsgs:05. Sending and receiving messages
POSIX Message Queuing can send and receive messages through the following two functions:
#include <mqueue.h> mqd_t mq_send (mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); c2/>//successfully returned 0, error returned-1 mqd_t mq_receive (mqd_t mqdes, Char *msg_ptr, size_t msg_len, unsigned *msg_prio); The number of bytes received for the message was successfully returned, error 1 #ifdef __use_xopen2k mqd_t mq_timedsend (mqd_t mqdes, const char *msg_ptr, size_t Msg_len, unsigned msg_prio, const struct TIMESPEC *abs_timeout); mqd_t mq_timedreceive (mqd_t mqdes, Char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct TIMESPEC * Abs_timeout); #endif
Where Mq_send writes a message to the message queue, Mq_receive reads a message from the message queue.
Mqdes: Message Queue descriptor;
MSG_PTR: Pointer to the message body buffer;
Msg_len: The length of the message body, where the mq_receive parameter cannot be less than the maximum size of the message that can be written to the queue, i.e. it must be greater than or equal to the mq_msgsize in the MQ_ATTR structure of the queue. If the Msg_len in mq_receive is less than this value, the Emsgsize error is returned. Poxis Message Queuing can send a message length of 0.
Msg_prio: The priority of the message; it is a number less than Mq_prio_max, the higher the value, the higher the priority. POSIX Message Queuing always returns the oldest message of the highest priority in the queue when calling Mq_receive. If the message does not need to be prioritized, the Msg_prio that Mq_send is set Msg_prio to 0,mq_receive can be null.
There are also two xsi defined extension interfaces that send and receive messages for a limited time: Mq_timedsend and mq_timedreceive functions. By default, Mq_send and mq_receive are blocked for invocation and can be set to O_nonblock by Mq_setattr.
The following is the test code used by Message Queuing:
#include <iostream> #include <cstring> #include <errno.h> #include <stdlib.h> #include < unistd.h> #include <fcntl.h> #include <mqueue.h> using namespace Std;int main () {mqd_t mqid;mqid = Mq_ope N ("/shltsh_queue", O_RDWR | O_creat | O_EXCL, 0666, NULL); if (Mqid < 0) {if (errno = = eexist) {mq_unlink ("/shltsh_queue"); mqid = Mq_open ("/shltsh_queue", o_rd WR | O_creat, 0666, NULL);} Else{cout << "open message Queue error." << strerror (errno) << endl;return-1;}} if (fork () = = 0) {mq_attr mqattr;mq_getattr (mqid, &mqattr); char *buf = new Char[mqattr.mq_msgsize];for (int i = 1; I &l t;= 5; ++i) {if (Mq_receive (Mqid, buf, Mqattr.mq_msgsize, NULL) < 0) {cout << "receive message failed."; cout << "Error info:" << strerror (errno) << endl;continue;} cout << "Receive Message" << I << ":" << buf << Endl; Exit (0);} Char msg[] = "Hello World", for (int i = 1; I <= 5; ++i) {if (Mq_send (MQID, MSG, sizeof (msg), I) < 0) {cout << "send Message" << I << "failed."; cout << "Error info:" << strerror (errno) << Endl;} cout << "Send Message" << I << "success." << Endl;sleep (1);}}
Compile:
[email protected] csdnblog]# g++ PIPE.CPP-LRT
Output:
Send message 1 success.
Receive Message 1:hello World
Send Message 2 success.
Receive Message 2:hello World
Send Message 3 success.
Receive Message 3:hello World
Send Message 4 success.
Receive Message 4:hello World
Send Message 5 success.
Receive Message 5:hello World
6. Restrictions on Message Queuing
The limitations of POSIX Message Queuing itself are mq_maxmsg and mq_msgsize in Mq_attr, respectively, to limit the maximum number of messages in a message queue and the maximum number of bytes per message. As already mentioned, these two parameters can be set when calling Mq_open to create a message queue. When this setting is limited by the kernel of the system.
The following is the limitation of the POSIX Message Queuing size of the shell to the boot process under Linux 2.6.32:
[Email protected] csdnblog]# Ulimit-a | grep message
POSIX message queues (bytes,-Q) 819200
The limit size is 800KB, which is the size of the entire message queue, not just the maximum number of messages * The maximum size of the message, but also the additional overhead of Message Queuing. We know that the default maximum number of messages and the maximum size of messages for the POSIX message queue under Linux 2.6.32 are:
Mq_maxmsg = 10
Mq_msgsize = 8192
To illustrate that the above limit size includes the additional overhead of Message Queuing, here is the test code:
#include <iostream> #include <cstring> #include <errno.h> #include <stdlib.h> #include <unis td.h> #include <fcntl.h> #include <mqueue.h> int main (int argc, char **argv) {mqd_t mqid;mq_attr Attr;att R.mq_maxmsg = Atoi (argv[1]); attr.mq_msgsize = Atoi (argv[2]); mqid = Mq_open ("/root/shltsh_queue", O_RDWR | O_creat | O_EXCL, 0666, &attr); if (Mqid < 0) {if (errno = = eexist) {mq_unlink ("/root/shltsh_queue"); mqid = Mq_open ("/root/ Shltsh_queue ", O_RDWR | O_creat, 0666, &attr); if (Mqid < 0) {std::cout << "open message Queue error." << strerror (errno) << ; std::endl;return-1;}} Else{std::cout << "open message Queue error." << strerror (errno) << std::endl;return-1;}} Mq_attr mqattr;if (mq_getattr (mqid, &mqattr) < 0) {std::cout << "get the Message Queue attribute error." <& Lt std::endl;return-1;} Std::cout << "mq_flags:" << mqattr.mq_flags << std::endl;std::cout << "mq_mAxmsg: "<< mqattr.mq_maxmsg << std::endl;std::cout <<" mq_msgsize: "<< mqattr.mq_msgsize < < Std::endl;std::cout << "MQ_CURMSGS:" << mqattr.mq_curmsgs << Std::endl;}
The following sets the maximum number of messages and the maximum message size to be tested when creating Message Queuing:
[email protected] csdnblog]#./a.out 10 81920
Open Message Queue error. Cannot allocate memory
[Email protected] csdnblog]#./a.out 10 80000
Open Message Queue error. Cannot allocate memory
[Email protected] csdnblog]#./a.out 10 70000
Open Message Queue error. Cannot allocate memory
[Email protected] csdnblog]#./a.out 10 60000
mq_flags:0
Mq_maxmsg:10
mq_msgsize:60000
mq_curmsgs:0
From the above you can see that Message Queuing really holds the size of the message data is not 819200B. You can modify the limit parameter to change the number of messages that the message queue can hold. The restrictions can be modified in the following way, but this will expire after the shell startup process ends and can be executed in a script that writes the settings to the boot startup, such as. bashrc,rc.local.
[Email protected] csdnblog]# ulimit-q 1024000000
[Email protected] csdnblog]# Ulimit-a | grep message
POSIX message queues (bytes,-q) 1024000000
Next, test the properties of the message queue that you can set:
[Email protected] csdnblog]#./a.out 10 81920
mq_flags:0
Mq_maxmsg:10
mq_msgsize:81920
mq_curmsgs:0
[Email protected] csdnblog]#./a.out 10 819200
mq_flags:0
Mq_maxmsg:10
mq_msgsize:819200
mq_curmsgs:0
[Email protected] csdnblog]#./a.out 10 8192
mq_flags:0
Mq_maxmsg:10
mq_msgsize:8192
mq_curmsgs:0
POSIX Message Queuing has two additional limitations on implementation:
Mq_open_max: The maximum number of message queues a process can open at the same time, POSIX requires at least 8;
Mq_prio_max: The maximum priority of the message, POSIX requires at least 32;
interprocess communication (6)-Message Queuing POSIX