As the functionality of and syntax for message queues is somewhat complex, they are ideal candidates for incorporation into a C++ class. A message queue class would define the relationships between message queue data and the functions ( methods ) that manipulate this data. A declaration of a simplified message queue class called Message_que is shown in Figure 6.10.
Figure 6.10 Header file for a basic message queue class.
File : Message_que.h /* A VERY simplified message queue class for use in a std UNIX environment. See the text for instructions on how to use this class. Copyright (c) 2002 J. S. Gray + Exit codes for class operations: 1 - Unable to create queue 2 - Cannot access queue 3 - Enque has failed 4 - Deque has failed 10 5 - Unable to remove queue */ #ifndef Message_que_h #define Message_que_h #define _GNU_SOURCE + #include #include #include #include #include 20 #include #include class Message_que { public: + Message_que (const char ='M'); // Constructor void Remove( ); // Remove the queue void Enque( void *, int ); // Place a message in the queue int Deque( void *, int, int ); // Obtain a message from queue bool Exist( const char ='M' ); // True if the queue exists 30 void Create( ); // Create the queue void Acquire( ); // Acquire access to the queue private: int msqid; // ID of message queue key_t ipckey; // Key from ftok + }; #endif
As defined, the Message_que class has seven public methods and three private data members . The functionality of each method is shown in Table 6.14.
The C++ code that implements the message queue class is found in the program file Message_que.cxx (Program 6.5). As shown, the code is bare boneslittle is done to handle errors, and only basic message queue functionality is addressed.
Table 6.14. Message_que Class Methods.
Method name |
Explanation |
---|---|
Message_que |
This is the class constructor. This method takes one argument, which, if specified, defaults to the value M . The constructor generates the message queue ID. |
Remove |
This method removes the message queue from the system. |
Enque |
Enque is used to add a message to the message queue. This method is passed a reference to the message and the message size (in bytes). |
Deque |
The Deque method removes a single message from the message queue. This method has three arguments: a reference to a structure to store the returned data, the maximum size of a returned message, and the message type. |
Exist |
This method returns a true or false as to whether or not the message queue exists. |
Create |
Create (generate) a new message queue. |
Acquire |
Gains access to the existing message queue. |
Program 6.5a Program code for the Message Queue Class.
File : Message_que.cxx /* Message queue implementationCopyright (c) 2002 J. S. Gray */ #include "Message_que.h" + #include // Message queue constructor. Message_que::Message_que( const char the_key ){ ipckey = ftok( ".", the_key ); 10 msqid = -1; } // Remove the message queue (if this process created it) void Message_que::Remove( ) { + if ( msgctl( msqid, IPC_RMID, (struct msqid_ds *) 0 ) == -1 ) exit( 5 ); } // Place a message in the message queue. void 20 Message_que::Enque( void *msg, int msg_size ){ if ( msgsnd( msqid, msg, msg_size, 0 ) == -1 ) exit( 3 ); } // Return a message from the message queue. + int Message_que::Deque( void *msg, int msg_size, int msg_type ){ int n; memset( msg, 0x0, msg_size ); // clear space if ( (n=msgrcv( msqid, msg, msg_size, msg_type, IPC_NOWAIT)) == -1 ) 30 exit( 4 ); return n; } // True if message queue exists else false. bool + Message_que::Exist( const char the_key ){ return (msgget(ipckey, 0) != -1); } // Generate a new message queue. void 40 Message_que::Create( ){ if ( (msqid=msgget(ipckey, IPC_CREAT0660)) == -1 ) exit( 1 ); } // Acquire (gain access to) existing message queue. + void Message_que::Acquire( ){ if ( (msqid=msgget(ipckey, 0)) == -1 ) exit( 2 ); }
To use this class, the files Message_que.h and Message_que.cxx should reside locally. The Message_que class is compiled into object code with the command line
linux$ g++ Message_que.cxx c
At the top of the source file that will use a Message_que object, add the statement
#include "Message_que.h"
to make the class definition available to the compiler. When compiling the source file, include the message queue object code file
linux$ g++ your_file_name.cxx Message_que.o
Program 6.6 demonstrates the use of a message queue object. This program allows command-line manipulation of a message queue. As such, the message queue could be used as a drop off and retrieval site for messages.
Program 6.6 A command-line message queue manipulation utility.
File : p6.6.cxx /* A message queue manipulation utility */ #include "Message_que.h" <-- 1 + #include #include #include using namespace std; 10 typedef struct { long int m_type; char m_text[1024]; } MESSAGE; extern char *optarg; + extern int optind, opterr, optopt; int main(int argc, char *argv[ ]){ int c; char optstring[] = "sri:m:"; <-- 2 20 opterr = 0; bool snd_msg=false, get_msg=false, rmv_que=false; char *the_message; // Allocate msg - clear text MESSAGE my_msg; + memset( my_msg.m_text, 0x0, 1024 ); // Allocate - acquire msg queue Message_que MQ('M'); if ( !MQ.Exist('M') ) MQ.Create( ); 30 else MQ.Acquire( ); // Process command line args while ((c = getopt(argc, argv, optstring)) != -1) switch (c) { + case 's': snd_msg=true; break; case 'r': get_msg=true; 40 break; case 'i': my_msg.m_type=atol(optarg); break; <-- 3 case 'm': + strcpy(my_msg.m_text,optarg); } if ( snd_msg && my_msg.m_type > 0 ){ MQ.Enque( &my_msg, strlen(my_msg.m_text)+1); cerr << "Added : " << my_msg.m_text << endl; 50 } else if ( get_msg && my_msg.m_type > 0 ){ MQ.Deque(&my_msg, 1024, my_msg.m_type); cerr << "Message: " << my_msg.m_text << endl; } else cerr << "Invalid command line option(s)" << endl; + return 0; }
(1) Include the Message_que class definition.
(2) Acceptable command-line options :
(3) Use the optarg reference to obtain the actual command-line data.
In line 4 of the program, the definition of the Message_que class is included. At line 10, the format of a message queue message is defined. Within the function main , the acceptable command-line options are assigned to the optstring array. The program accepts two standard-format command-line options. The -s option indicates a message is to be sent to the message queue, while r means a message should be read from the message queue. Theremaining two options of the program require arguments. The i option is to be followed with the message queue ID (type), and the m option is to be followed with an actual message. If the message is more than one word, it should be surrounded with quotes.
A while loop and the getopt library function are used to parse command-line options. If the user indicates a message is to be sent, the message type ( i ) and the actual message ( -m ) must be specified. If a message is to be retrieved, then just the message type ( -i ) must be indicated. The program informs the user of its activity, including a message that indicates when an improper set of command-line options has been passed. Figure 6.11 demonstrates the use of Program 6.6.
Figure 6.11 Manipulating a message queue from the command line.
linux$ ipcs -q ------ Message Queues ------ <-- 1 key msqid owner perms used-bytes messages linux$ p6.6 -i 98 -s -m "Don't forget the fish!" <-- 2 Added : Don't forget the fish! linux$ p6.6 -i 98 -s -m "See you Wednesday -jg <-- 2 Added : See you Wednesday -jg linux$ p6.6 -s -i 72 -m "Paper due on the 16th" <-- 2 Added : Paper due on the 16th linux$ ipcs -q ------ Message Queues ------ <-- 2 key msqid owner perms used-bytes messages 0x4d15ae86 4718592 gray 660 67 3 linux$ p6.6 -r -i 98 Message: Don't forget the fish! <-- 3 linux$ p6.6 -r -i 98 Message: See you wednesday -jg linux$ ipcs -q ------ Message Queues ------ key msqid owner perms used-bytes messages 0x4d15ae86 4718592 gray 660 22 1 linux$ ipcs -q -i 4718592 Message Queue msqid=4718592 <-- 4 uid=500 gid=1000 cuid=500 cgid=1000 mode=0660 cbytes=22 qbytes=16384 qnum=1 lspid=17306 lrpid=17309 send_time=Sun Mar 10 17:06:40 2002 rcv_time=Sun Mar 10 17:06:40 2002 change_time=Sun Mar 10 17:06:40 2002
(1) At the start, no message queues in the system.
(2) Add some messages to the message queue.
(2) Three messages now in the queue.
(3) Retrieve the first two messages of type 98.
(4) What the system knows about this message queue.
Programs and Processes
Processing Environment
Using Processes
Primitive Communications
Pipes
Message Queues
Semaphores
Shared Memory
Remote Procedure Calls
Sockets
Threads
Appendix A. Using Linux Manual Pages
Appendix B. UNIX Error Messages
Appendix C. RPC Syntax Diagrams
Appendix D. Profiling Programs