一旦我们有了队列标识符,我们就可以开始对其执行操作。 要将消息传递到队列,您可以使用msgsnd系统调用
SYSTEM CALL: msgsnd(); PROTOTYPE: int msgsnd ( int msqid, struct msgbuf *msgp, int msgsz, int msgflg ); RETURNS: 0 on success -1 on error: errno = EAGAIN (queue is full, and IPC_NOWAIT was asserted) EACCES (permission denied, no write permission) EFAULT (msgp address isn't accessable - invalid) EIDRM (The message queue has been removed) EINTR (Received a signal while waiting to write) EINVAL (Invalid message queue identifier, nonpositive message type, or invalid message size) ENOMEM (Not enough memory to copy message buffer) NOTES:
的msgflg参数可以设置为 0(忽略),或者
如果消息队列已满,则消息不会写入队列,控制权返回给调用进程。 如果未指定,则调用进程将挂起(阻塞),直到消息可以写入为止。
让我们创建另一个用于发送消息的包装函数
int send_message( int qid, struct mymsgbuf *qbuf ) { int result, length; /* The length is essentially the size of the structure minus sizeof(mtype) */ length = sizeof(struct mymsgbuf) - sizeof(long); if((result = msgsnd( qid, qbuf, length, 0)) == -1) { return(-1); } return(result); }
#include <stdio.h> #include <stdlib.h> #include <linux/ipc.h> #include <linux/msg.h> main() { int qid; key_t msgkey; struct mymsgbuf { long mtype; /* Message type */ int request; /* Work request number */ double salary; /* Employee's salary */ } msg; /* Generate our IPC key value */ msgkey = ftok(".", 'm'); /* Open/create the queue */ if(( qid = open_queue( msgkey)) == -1) { perror("open_queue"); exit(1); } /* Load up the message with arbitrary test data */ msg.mtype = 1; /* Message type must be a positive number! */ msg.request = 1; /* Data element #1 */ msg.salary = 1000.00; /* Data element #2 (my yearly salary!) */ /* Bombs away! */ if((send_message( qid, &msg )) == -1) { perror("send_message"); exit(1); } }
现在我们的队列中有一条消息,请尝试ipcs命令来查看队列的状态。 现在让我们将讨论转向从队列中实际检索消息。 为此,您可以使用msgrcv()系统调用
SYSTEM CALL: msgrcv(); PROTOTYPE: int msgrcv ( int msqid, struct msgbuf *msgp, int msgsz, long mtype, int msgflg ); RETURNS: Number of bytes copied into message buffer -1 on error: errno = E2BIG (Message length is greater than msgsz, no MSG_NOERROR) EACCES (No read permission) EFAULT (Address pointed to by msgp is invalid) EIDRM (Queue was removed during retrieval) EINTR (Interrupted by arriving signal) EINVAL (msgqid invalid, or msgsz less than 0) ENOMSG (IPC_NOWAIT asserted, and no message exists in the queue to satisfy the request) NOTES:
msgsz = sizeof(struct mymsgbuf) - sizeof(long);
如果将 IPC_NOWAIT 作为标志传递,并且没有消息可用,则该调用将向调用进程返回 ENOMSG。 否则,调用进程将阻塞,直到队列中收到满足msgrcv()参数的消息。 如果在客户端等待消息时删除队列,则返回 EIDRM。 如果进程在阻塞并等待消息到达的过程中捕获到信号,则返回 EINTR。
让我们检查一个用于从队列中检索消息的快速包装函数
int read_message( int qid, long type, struct mymsgbuf *qbuf ) { int result, length; /* The length is essentially the size of the structure minus sizeof(mtype) */ length = sizeof(struct mymsgbuf) - sizeof(long); if((result = msgrcv( qid, qbuf, length, type, 0)) == -1) { return(-1); } return(result); }
在msgflg参数中的 MSG_NOERROR 位提供了一些额外的功能。 如果物理消息数据的大小大于msgsz,并且断言了 MSG_NOERROR,则将截断消息,并且仅返回msgsz个字节。 通常,msgrcv()系统调用返回 -1 (E2BIG),并且该消息将保留在队列中以供以后检索。 此行为可用于创建另一个包装函数,该函数将允许我们``窥视''队列内部,以查看是否已收到满足我们请求的消息
int peek_message( int qid, long type ) { int result, length; if((result = msgrcv( qid, NULL, 0, type, IPC_NOWAIT)) == -1) { if(errno == E2BIG) return(TRUE); } return(FALSE); }