消息队列是进程间通讯的一种方法,一开始我以为消息队列是类似一个管道,一头连接一个进程、一头连接另一个进程,只能由这两个进程来进行互相的读写,其实这是错的,消息队列是系统层面的,它不属于某两个进程,它是由系统维护的一个链表结构,对消息队列的读写就是一个对链表的操作,默认是在链表的一端写数据,另一端读数据(先进先出),进程也可以取指定某种消息类型的消息.
在一个进程里创建了消息队列,且是可读可写的,那么系统中的所有进程都可以对它进行读写操作.
1、打开或创建一个消息队列
原型:int msgget(key_t key, int msgflg);
参数:
1)key:消息队列的key值。
2)msgflg:
IPC_CREAT:如果key对应的消息队列对象不存在,则创建,否则则进行打开操作,返回0.
IPC_EXCL:如果key对应的消息队列对象不存在,则返回-1;否则则进行打开操作,返回0。
权限控制:0666表示可读可写,和上面的IPC_CREAT做逻辑或操作.
返回值:成功返回,创建的或打开的消息队列的id,失败返回-1.
例子程序:test1.c,代码如下:
- #include<sys/types.h>
- #include<sys/ipc.h>
- #include<sys/msg.h>
- #include<stdio.h>
- intmain(void)
- {
- intmsgid;
- printf("thisistest1!\n");
- msgid=msgget(1001,0666|IPC_CREAT);
- printf("msgid=%d\n",msgid);
- return0;
- }
执行结果:
- [root@server~]#gcc-otest1test1.c
- [root@server~]#./test1
- thisistest1!
- msgid=32768
- [root@server~]#ipcs
- ------SharedMemorySegments--------
- keyshmidownerpermsbytesnattchstatus
- ------SemaphoreArrays--------
- keysemidownerpermsnsems
- 0x000000000root6001
- ------MessageQueues--------//phpfensi.com
- keymsqidownerpermsused-bytesmessages
- 0x000003e932768root66600
从ipcs命令的结果可以知道,消息队列在创建它的进程退出后,还存在于系统中,说明消息队列是系统一层的,并不是属于某个进程的.
2、设置消息队列属性(包括删除)
原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
1)msqid:消息队列的id.
2)cmd:执行的控制命令.
IPC_STAT:读取消息队列属性,取得此队列的msqid_ds 结构,并将其存放在buf指向的结构中.
IPC_SET:设置消息队列属性.
IPC_RMID:删除消息队列.
IPC_INFO:读取消息队列基本情况,此命令等同于 ipcs 命令.
例子程序:test2.c,代码如下:
- #include<sys/types.h>
- #include<sys/ipc.h>
- #include<sys/msg.h>
- #include<stdio.h>
- intmain(void)
- {
- inti;
- printf("thisistest2!\n");
- i=msgctl(32768,IPC_RMID,NULL);//这里已经知道消息id等于32768
- if(0==i)
- {
- printf("msqdeleted!\n");
- }
- return0;
- }
- //执行结果:
- [root@server~]#gcc-otest2test2.c
- [root@server~]#./test2
- thisistest2!
- msqdeleted!
- [root@server~]#ipcs
- ------SharedMemorySegments--------
- keyshmidownerpermsbytesnattchstatus
- ------SemaphoreArrays--------
- keysemidownerpermsnsems
- 0x000000000root6001
- ------MessageQueues--------
- keymsqidownerpermsused-bytesmessages
原有的消息队列被删除了.
3、向消息队列写/读消息
原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:
1)msqid:消息队列的id.
2)msgp:指向消息缓冲区的指针,该指针指向如下的一个用户可定义的通用结构.
- structmymsg{
- longmtype;
- charmbuf[1024];
- };
3)msgsz:消息的大小。
4)msgflg:可以为IPC_NOWAIT或0,表示操作是阻塞式的还是非阻塞式的,设置为IPC_NOWAIT,在msgsnd()中,如果消息队列已经满了,则不会阻塞,立即返回-1(EAGAIN).
在msgrcv()中,如果消息队列为空,则不做等待,立即返回-1(ENOMSG),设置为0,在msgsnd()中,进程阻塞直到(a)有空间可以容纳要发送的消息;或(b)从系统中删除了此队列(返回EIDRM);或(c)捕捉到一个信号,并从信号处理程序返回(返回EINTR)。
在msgrcv()中,进程阻塞直到(a)有了指定类型的消息;或(b)从系统中删除了此队列(返回EIDRM);或(c)捕捉到一个信号并从信号处理程序返回(返回EINTR)。
5)msgtype:用于msgrcv()函数,指定消息的类型。相当于区分消息类别的标志位。
msgtype = 0,返回消息队列中的第一个消息。
返回值:
msgsnd(),成功返回0,出错返回-1。
msgrcv(),成功返回消息数据部分的长度,出错返回-1。
例子程序:test3.c,代码如下:
- #include<sys/types.h>
- #include<sys/ipc.h>
- #include<sys/msg.h>
- #include<stdio.h>
- #include<errno.h>
- typedefstruct
- {
- longmtype;
- charmbuf[1024];
- }mymsg;
- intmain(void)
- {
- inti;
- intmsgid1,msgid2;
- mymsgmessage1,message2,message3;
- printf("thisistest3!\n");
- msgid1=msgget(1002,0666|IPC_CREAT);//key1002
- if(msgid1<0)
- {
- printf("createkey=1002error,errno=%d\n",errno);
- exit(-1);
- }
- msgid2=msgget(1003,0666|IPC_CREAT);//key1003
- if(msgid2<0)
- {
- printf("createkey=1003error,errno=%d\n",errno);
- exit(-1);
- }
- //初始化
- message1.mtype=1;//设定一个消息类型
- memcpy(message1.mbuf,"firstmessage",13);
- message3.mtype=1;
- memcpy(message3.mbuf,"hellotest4.",12);
- //test3进程在msgid1上发消息
- i=msgsnd(msgid1,(void*)&message1,strlen(message1.mbuf)+1,0);
- if(i<0)
- {
- printf("sendmessage1error,errno=%d\n",errno);
- exit(-1);
- }
- //test3进程从msgid1取消息,存到message2中
- i=msgrcv(msgid1,(void*)&message2,1024,0,0);
- if(i<0)
- {
- printf("reverror,errno=%d\n",errno);
- exit(-1);
- }
- else
- {
- //显示取出的消息
- printf("%s\n",message2.mbuf);
- }
- //test3进程在msgid2上发消息
- i=msgsnd(msgid2,(void*)&message3,strlen(message3.mbuf)+1,0);
- if(i<0)
- {
- printf("sendmessage3error,errno=%d\n",errno);
- exit(-1);
- }
- return0;
- }
例子程序:test4.c,代码如下:
- #include<sys/types.h>
- #include<sys/ipc.h>
- #include<sys/msg.h>
- #include<stdio.h>
- #include<errno.h>
- typedefstruct
- {
- longmtype;
- charmbuf[1024];
- }mymsg;
- intmain(void)
- {
- inti,j;
- mymsgmessage;
- printf("thisistest4!\n");
- i=msgget(1003,0666|IPC_CREAT);
- if(i<0)
- {
- printf("createkey=1003error,errno=%d\n",errno);
- exit(-1);
- }
- //test4进程在key=1003的消息队列上取消息
- j=msgrcv(i,(void*)&message,1024,0,0);
- if(j<0)
- {
- printf("reverror,errno=%d\n",errno);
- exit(-1);
- }
- else
- {
- //显示取出的消息
- printf("%s\n",message.mbuf);
- }
- return0;
- }
开两个终端,一个执行test3,另一个执行test4.
test3执行结果,代码如下:
- [root@server~]#./test3
- thisistest3!
- firstmessage
ipcs命令能看到key=1003的消息队列中有一条消息,使用了13字节长度,代码如下:
- keymsqidownerpermsused-bytesmessages
- 0x000003ea98305root66600
- 0x000003eb131074root666131
- //test4执行结果:
- [root@server~]#./test4
- thisistest4!
- hellotest4.
以上.