1. An overview of the
- The handle used to refer to the message queue is an identifier returned by the msgget() call. These identifiers are different from the file description.
- Communication in message queues is message-oriented, meaning that the reader receives the entire message written by the writer. That is, you cannot read only part of a message or multiple messages at once.
- In addition to containing data, each message has a type represented as an integer.
2. Create or open a message queue
#include<sys/types.h>
#include<sys/msg.h>
int msgget(key_t key,int msgflg);
//return message queue identifier on success,or -1 on error
Copy the code
-
Key: The parameter can be set to IPC_PRIVATE. The system will create a new IPC object, or use ftok() to generate a (nearly unique) key. If the key is the same, the system will return an IPC object with the same key.
-
MSGFLG: bitmask to specify permissions imposed on new message queues and check permissions on an existing queue (similar to file permissions)
- IPC_CREAT: If there is no message queue corresponding to the specified key, a new queue is created, otherwise the created queue is returned
- IPC_EXCL: Used with IPC_CREAT. If the queue corresponding to the specified key already exists, the call will fail and return an EEXIST error.
Create a message queue
int msqid=msgget(IPC_PRIVATE,IPC_CREAT|S_IRUSR|S_IWUSR); //Read and Write by ownerif(msqid==-1){
errExit("msgget");
}
Copy the code
3. Exchange messages
The MSGSND () and MSGRCV () system calls perform I/O on the message queue. The first argument received by both system calls is the message queue identifier (MSQID). MSGP is a pointer to a programmer-defined structure used to hold messages that are sent or received. The general form of the structure is as follows:
struct msg{
long type; //messagetypevoid* body; //message body ... }Copy the code
The first part of the message must indicate the type of the message, represented as an integer of type Long, while the rest of the message is a custom structure that can be arbitrary in length, content, field name, and type, or multiple fields.
It is important to note that the size of the message is the size of all fields except the Type field
3.1 Sending Messages
Writing a message from a message queue requires write permission on the queue
#include<sys/types.h>
#include<sys/msg.h>
int msgsnd(int msqid,const void *msgp,size_t msgsz, int msgflg);
//return 0 on success,or -1 on error
Copy the code
To send a message using MSGSND (), you must set the type field value in the message structure to a value greater than 0 and copy the information you want to pass into your custom body field.
-
Msqid Specifies the queue identifier
-
Structure pointer to an MSGP message
-
The MSGSZ parameter specifies the number of bytes that the body field contains, which is the size of the message.
-
MSGFLG is a bitmask for a set of flags used to control MSGSND () operations
- IPC_NOWAIT: Performs a non-blocking send operation: when the message queue is full, MSGSND () blocks until there is enough space in the queue to hold the message. If this message is specified, MSGSND () immediately returns an EAGAIN error
Send a message using MSGSND ()
struct mbuf{
long mtype; //message typechar mtext[1024]; //message body } struct mbuf msg; int msqid,msgLen; . msgLen=strlen(msg.mtext);if(msgsnd(msqid,&msg,msgLen,IPC_NOWAIT)==-1){
errExit("msgsnd"); }...Copy the code
3.2 Receiving Messages
Reading a message from a message queue requires read permission on the queue
#include<sys/types.h>
#include<sys/msg.h>
ssize_t msgrcv(int msqid,void *msgp,size_t maxmsgsz,long msgtyp,int msgflg);
//return number of bytes copied into body field, or -1 on error
Copy the code
-
Msqid Specifies the queue identifier
-
The maxMSgsz parameter value must be greater than or equal to the size of the message to be read
-
The maximum free space for messages in the MSGP buffer is specified by the maxMSgz parameter. If the size of the message body to be deleted in the queue exceeds maxMSGSZ bytes, the message is not removed from the queue and error E2BIG is returned.
-
The order in which mTYPE reads the messages can be selected based on the MTYPE field
-
Mshtyp ==0 will delete the first message in the queue and return it to the calling process.
-
Msgtyoe >0 Deletes the message whose type field in the first message in the queue equals msgtype and returns it to the process. Can be used to have each process select a message that matches its own process ID, thus competing to read the same message.
-
Msgtype <0 turns the queue into a priority queue, or minimum heap form. The first message in the queue whose message type is the smallest and whose value is less than or equal to the absolute value of MSgType is deleted and returned to the calling process, if not blocked until a matching message appears.
-
-
MSGFLG controls the MSGRCV () operation
- IPC_NOWAIT performs a non-blocking receive. If there are no matching messages in the queue, it will be blocked. Setting this flag immediately returns an ENOMSG error.
- MSG_EXCEPT needs msgType >0 to work so that the first message returned by the queue whose type is not msgType is deleted and returned to the calling process (Linux specific).
- MSG_NOERROR An E2BIG error will be returned if the size of the message to be read exceeds the available space. Setting this flag will truncate the message size to maxMSgsZ bytes, which will be returned to the caller and the rest of the message will be discarded.
Read a message with MSGRCV ()
struct mbuf{ long mtype; char mtext[1024]; } int msqid,msgLen; struct mbuf msg; . MsgLen = MSGRCV (msqid, & MSG, 1024, 0, IPC_NOWAIT);if(msgLen==-1){
errExit("msgrcv");
}
Copy the code
4. Message queue control operations
#include<sys/types.h>
#include<sys/msg.h>
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
// return 0 on success,or -1 on error
Copy the code
- The CMD parameter specifies the operations to be performed on the queue.
- IPC_RMID immediately deletes the message queue object and its associated MSQID_DS data structure, and all messages in the queue are lost, blocked reader and writer processes wake up immediately, MSGSND () and MSGRCV fail and return an error EIDRM. This operation ignores the buF argument passed in.
- IPC_STAT puts a copy of the MSQID_DS data structure associated with the message queue into buF.
- IPC_SET updates the fields of the QUEUE associated MSQID_DS data structure with the values provided by BUF.
There are a few other CMD parameters that you are interested in, but only the common ones are listed here.
Delete the System V message queue using MSGCTL
.if(msgctl(msqid,IPC_RMID,NULL)==-1){
errExit("msgctl");
}
Copy the code
4.1 Data structures associated with message queues
struct msqid_ds
{
struct ipc_perm msg_perm; /* structure describing operation permission */
__time_t msg_stime; /* time of last msgsnd command */
__time_t msg_rtime; /* time of last msgrcv command */
__time_t msg_ctime; /* time of last change */
__syscall_ulong_t __msg_cbytes; /* current number of bytes on queue */
msgqnum_t msg_qnum; /* number of messages currently on queue */
msglen_t msg_qbytes; /* max number of bytes allowed on queue */
__pid_t msg_lspid; /* pid of last msgsnd() */
__pid_t msg_lrpid; /* pid of last msgrcv() */
__syscall_ulong_t __glibc_reserved4;
__syscall_ulong_t __glibc_reserved5;
};
struct ipc_perm
{
__key_t __key; /* Key. */
__uid_t uid; /* Owner's user ID. */ __gid_t gid; /* Owner's group ID. */
__uid_t cuid; /* Creator's user ID. */ __gid_t cgid; /* Creator's group ID. */
unsigned short int mode; /* Read/write permission. */
unsigned short int __pad1;
unsigned short int __seq; /* Sequence number. */
unsigned short int __pad2;
__syscall_ulong_t __glibc_reserved1;
__syscall_ulong_t __glibc_reserved2;
};
Copy the code
Modifies the MSG_qbytes setting for a System V message queue
. struct msqid_ds ds; int msqid; .if(msgctl(msqid,IPC_STAT,&ds)==-1){
errExit("msgctl");
}
ds.msg_qbytes=1048576 //1MB
if(msgctl(msqid,IPC_SET,&ds)==-1){
errExit("msgctl");
}
Copy the code
5. Limits on message queues
- MSGMNI specifies the number of message queues that can be created in the system.
- MSGMAX specifies the maximum number of bytes that can be written to a single message (writing messages beyond this value returns an EINVAL error).
- MSGMNB specifies the maximum number of bytes that can be held in a message queue and is used to initialize the MSG_qbytes field of the MSQID_DS data structure. If the MSG_qbytes limit for a queue is reached, MSGSND () blocks or returns an EAGAIN error when setting IPC_NOWAIT.
There are some other restrictions that you may be interested in checking out online, but here are the common ones.
The Linux-specific MSGCTL () IPC_INFO operation gets a structure of type MSginfo that contains values for various message queue limits
struct msginfo buf;
msgctl(0, IPC_INFO,(struct msqid_ds *)&buf);
/* buffer for msgctl calls IPC_INFO, MSG_INFO */
struct msginfo
{
int msgpool;
int msgmap;
int msgmax;
int msgmnb;
int msgmni;
int msgssz;
int msgtql;
unsigned short int msgseg;
};
Copy the code
6. Implement file server applications using message queues
Server-side core code
.for(;;) {msgLen = MSGCRV (serverId, & the req, REQ_MSG_SIZE, 0, 0).if(msgLen==-1){
if(errno==EINTR)//Interrupted by SIGCHLD handler?
continue;
errMsg("msgrcv");
break;
}
pid=fork();
if(pid==-1){
errMsg("fork");
break;
}
if(pid==0){ serveRequest(&req); _exit(EXIT_SUCCESS); }}...Copy the code
Client core code
. clientId=msgget(IPC_PRIVATE,S_IRUSR|S_IWUSR|S_IWGRP); // Make sure the server has write permission... MsgLen = MSGRCV (clientId, & the req, RESP_MSG_SIZE, 0, 0).if(msgLen==-1){
errExit("msgrcv"); }...for(;;) {msgLen = MSGRCV (clientId, & resp, RESP_MSG_SIZE, 0, 0).if(msgLen==-1){
errExit("msgrcv"); }... }...Copy the code
7. Disadvantages of System V message queues
-
Message queues are referenced by identifiers rather than file descriptors like most other UNIX I/O mechanisms. This means that the various file description-based I/O techniques such as SELECT (), poll(), and epoll will not apply to message queues. In addition, it is more complicated to write code in a program that handles both the input to the message queue and the file descriptor-based I/O mechanism than it is to write code that handles file descriptors alone.
-
Using keys instead of file names to identify message queues adds additional programming complexity. The ftok() function usually produces a unique key, but it is not guaranteed. Using the IPC_PRIVATE key ensures that a unique queue identifier is produced, but the identifier needs to be visible to other processes that need to use it.
-
Message queues are connectionless, and the kernel does not treat the number of processes maintaining reference queues the way pipes, FIFOS, and sockets do, causing several problems:
- When can an application safely delete a message queue?
- How can an application ensure that queues that are no longer in use are deleted?
-
The total number of message queues, the size of messages, and the capacity of a single queue are all limited. These limits are configurable, but if an application is outside the scope of these default limits, some additional work needs to be done when installing the application.