消息队列常用命令:
ipcs -q
ipcs -l
ipcrm -q
消息队列函数由msgget、msgctl、msgsnd、msgrcv四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。
1. msgget函数原型
如果用msgget创建了一个新的消息队列对象时,则msqid_ds结构成员变量的值设置如下:
msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime设置为0。
msg_ctime设置为当前时间。
msg_qbytes设成系统的限制值。
msgflg的读写权限写入msg_perm.mode中。
msg_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
2. msgctl函数原型
3. msgsnd函数原型
msgsnd()为阻塞函数,当消息队列容量满或消息个数满会阻塞。消息队列已被删除,则返回EIDRM错误;被信号中断返回E_INTR错误。
如果设置IPC_NOWAIT消息队列满或个数满时会返回-1,并且置EAGAIN错误。
msgsnd()解除阻塞的条件有以下三个条件:
① 不满足消息队列满或个数满两个条件,即消息队列中有容纳该消息的空间。
② msqid代表的消息队列被删除。
③ 调用msgsnd函数的进程被信号中断。
4. msgrcv函数原型
msgrcv()解除阻塞的条件有以下三个:
① 消息队列中有了满足条件的消息。
② msqid代表的消息队列被删除。
③ 调用msgrcv()的进程被信号中断。
消息队列使用程序范例
5. 消息队列控制范例
msgctl.c源代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <error.h>
#define TEXT_SIZE 512
struct msgbuf
{
long mtype ;
char mtext[TEXT_SIZE] ;
} ;
int main(int argc, char **argv)
{
int msqid ;
struct msqid_ds info ;
struct msgbuf buf ;
struct msgbuf buf1 ;
int flag ;
int sendlength, recvlength ;
msqid = msgget( IPC_PRIVATE, 0666 ) ;
if ( msqid < 0 )
{
perror("get ipc_id error") ;
return -1 ;
}
buf.mtype = 1 ;
strcpy(buf.mtext, "happy new year!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
}
buf.mtype = 3 ;
strcpy(buf.mtext, "good bye!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
}
flag = msgctl( msqid, IPC_STAT, &info ) ;
if ( flag < 0 )
{
perror("get message status error") ;
return -1 ;
}
printf("uid:%d, gid = %d, cuid = %d, cgid= %d " ,
info.msg_perm.uid, info.msg_perm.gid, info.msg_perm.cuid, info.msg_perm.cgid ) ;
printf("read-write:%03o, cbytes = %lu, qnum = %lu, qbytes= %lu " ,
info.msg_perm.mode&0777, info.msg_cbytes, info.msg_qnum, info.msg_qbytes ) ;
system("ipcs -q") ;
recvlength = sizeof(struct msgbuf) - sizeof(long) ;
memset(&buf1, 0x00, sizeof(struct msgbuf)) ;
flag = msgrcv( msqid, &buf1, recvlength ,3,0 ) ;
if ( flag < 0 )
{
perror("recv message error") ;
return -1 ;
}
printf("type=%d, message=%s ", buf1.mtype, buf1.mtext) ;
flag = msgctl( msqid, IPC_RMID,NULL) ;
if ( flag < 0 )
{
perror("rm message queue error") ;
return -1 ;
}
system("ipcs -q") ;
return 0 ;
}
编译 gcc msgctl.c –o msgctl。
执行 ./msg,执行结果如下:
uid:1008, gid = 1003, cuid = 1008, cgid= 1003
read-write:666, cbytes = 1024, qnum = 2, qbytes= 163840
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00000000 65536 zjkf 666 1024 2
type=3, message=good bye!
------ Message Queues --------
key msqid owner perms used-bytes messages
6. 两进程通过消息队列收发消息
(1)发送消息队列程序
msgsnd.c源代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <time.h>
#define TEXT_SIZE 512
struct msgbuf
{
long mtype ;
int status ;
char time[20] ;
char mtext[TEXT_SIZE] ;
} ;
char *getxtsj()
{
time_t tv ;
struct tm *tmp ;
static char buf[20] ;
tv = time( 0 ) ;
tmp = localtime(&tv) ;
sprintf(buf,"%02d:%02d:%02d",tmp->tm_hour , tmp->tm_min,tmp->tm_sec);
return buf ;
}
int main(int argc, char **argv)
{
int msqid ;
struct msqid_ds info ;
struct msgbuf buf ;
struct msgbuf buf1 ;
int flag ;
int sendlength, recvlength ;
int key ;
key = ftok("msg.tmp", 0x01 ) ;
if ( key < 0 )
{
perror("ftok key error") ;
return -1 ;
}
msqid = msgget( key, 0600|IPC_CREAT ) ;
if ( msqid < 0 )
{
perror("create message queue error") ;
return -1 ;
}
buf.mtype = 1 ;
buf.status = 9 ;
strcpy(buf.time, getxtsj()) ;
strcpy(buf.mtext, "happy new year!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
}
buf.mtype = 3 ;
buf.status = 9 ;
strcpy(buf.time, getxtsj()) ;
strcpy(buf.mtext, "good bye!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
}
system("ipcs -q") ;
return 0 ;
}
(2)接收消息队列程序
msgrcv.c源代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define TEXT_SIZE 512
struct msgbuf
{
long mtype ;
int status ;
char time[20] ;
char mtext[TEXT_SIZE] ;
} ;
int main(int argc, char **argv)
{
int msqid ;
struct msqid_ds info ;
struct msgbuf buf1 ;
int flag ;
int recvlength ;
int key ;
int mtype ;
key = ftok("msg.tmp", 0x01 ) ;
if ( key < 0 )
{
perror("ftok key error") ;
return -1 ;
}
msqid = msgget( key, 0 ) ;
if ( msqid < 0 )
{
perror("get ipc_id error") ;
return -1 ;
}
recvlength = sizeof(struct msgbuf) - sizeof(long) ;
memset(&buf1, 0x00, sizeof(struct msgbuf)) ;
mtype = 1 ;
flag = msgrcv( msqid, &buf1, recvlength ,mtype,0 ) ;
if ( flag < 0 )
{
perror("recv message error ") ;
return -1 ;
}
printf("type=%d,time=%s, message=%s ", buf1.mtype, buf1.time, buf1.mtext) ;
system("ipcs -q") ;
return 0 ;
}
(3)编译与执行程序
① 在当前目录下利用>msg.tmp建立空文件msg.tmp。
② 编译发送消息队列程序 gcc msgsnd.c -o msgsnd。
③ 执行./msgsnd,执行结果如下:
----- Message Queues --------
key msqid owner perms used-bytes messages
0x0101436d 294912 zjkf 600 1072 2
④ 编译接收消息程序 gcc msgrcv.c -o msgrcv
⑤ 执行./msgrcv,执行结果如下:
type=1,time=03:23:16, message=happy new year!
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0101436d 294912 zjkf 600 536 1
⑥ 利用ipcrm -q 294912删除该消息队列。因为消息队列是随内核持续存在的,在程序中若不利用msgctl函数或在命令行用ipcrm命令显式地删除,该消息队列就一直存在于系统中。另外信号量和共享内存也是随内核持续存在的。
摘录自《深入浅出Linux工具与编程》