您的位置:首页 > 运维架构 > Linux

Linux IPC 之消息队列

2015-06-04 20:32 645 查看
今天学习了一下Linux中的消息队列。

消息队列可能是Linux IPC中最具有数据交换功能的通信方式。消息队列是一个消息的链表,我们创建一个消息队列,然后把想要发送的消息放入队列,别动进程就可以从消息队列中读取消息。

消息队列链表由系统内核进行维护,它可以通过一个消息的类型来检索指定的数据,它在数据流的概念上扩展了数据传递的概念,可以根据需要读取指定的数据,这是管道和FIFO所不能的。

但是消息队列的缺点也很明显,要维护该消息链表,就要占用更多的内存资源,时间开销也大一些。

可以使用msgget()函数来创建一个 消息队列,原型如下:

int msgget(key_t key,int flags);

|—-key用来转换成一个标识符,每一个消息队列都与一个key对应;

|—-flags表明函数的行为。可以是IPC_CREAT、IPC_NOWAIT、IPC_EXCL或者三个或

该函数成功返回消息队列ID。

可以使用msgctl()函数在创建的消息队列上进行各种操作。原型如下:

int msgctl(int msqid,int cmd,struct msqid_ds *buf);

|—-msqid:要进行操作的消息队列的ID;

|—-cmd:要在消息队列上进行的操作;

cmd的取值及操作:

IPC_STAT:—-取队列的msqid_ds结构体,把它存放在buf所指的结构中。

IPC_SET:——-使用buf所指结构体中的值对当前队列的相关结构成员进行赋值。

IPC_RMID:——删除消息队列,并清除消息队列中所有消息,该操作会影响后面进程对该消息队列

的相关操作。

|——buf:一个指向struct msqid_ds结构的指针,该结构体描述了当前消息队列的当前状态。在cmd中的某些 操作需要用该结构体。

向队列写入消息:

int msgsnd(int msqid,const void* ptr,size_t nbytes,int flags);

|—-msqid:要进行操作的队列。

|—-ptr:指向一个 msgbuf结构体:struct msgbuf{long mtype;char mbuf[];};只是一个模板的消息结 构。mbuf是一个字符数组,长度根据消息来定。mtype是消息类型。

|—–nbytes:消息的长度。

|—-flags:函数的行为

函数执行成功返回0,失败返回-1并设置errno,errno可能的值有:EAGAIN,EACCES,EFAULT,EIDRM,EINTR,EINVAL,ENOMEN.

从队列读取消息:

ssize_t msgrcv(int msqid,void *ptr,size_t nbytes,long type,int flags);

|

|—–msqid:指定要读取消息的队列。

|

|—–ptr:接收数据的缓冲区。

|

|—–nbytes:要接收的数据的长度。

|

|—-type:指定msgrcv()函数所要读取的消息

|—-type>0:返回消息类型与type相等的第一条消息

|—-type=0:返回消息队列头部的消息

|—-tpye<0:返回消息类型小于等于type绝对值的最小值的第一条消息。

|

|—–flags:如果设置了IPC_NOWAIT标志位,则当队列中无符合条件的消息时,函数出错返回;否则,直到出现满足条件的消息为止,然后函数读取消息返回。

下面是一段简单的测试代码:

1 #include<sys/msg.h>
2 #include<sys/types.h>
3 #include<sys/ipc.h>
4 #include<stdio.h>
5 #include<stdlib.h>
6
7 #define BUFSZ 4096//接收缓冲区大小
8
9 struct msg{
10 long msg_types;
11 char msg_buf[511];
12 };//定义消息模板
13 int main(void)
14 {
15     int qid;//消息队列ID
16     int pid;//进程ID
17     int len;//消息长度
18     struct msg pmsg;//消息模板变量
19
20     pmsg.msg_types = getpid();//消息类型为进程的ID
21     sprintf(pmsg.msg_buf,"Hello!this is :%d\n\0",getpid());//打印来自进程的消息
22     len = strlen(pmsg.msg_buf);//获取消息长度
23
24     if((qid = msgget(IPC_PRIVATE,IPC_CREAT|0666))<0)//创建消息队列
25     {
26         perror("MSGGET error");
27         exit(1);
28     }
29     printf("create queue:%d\n",qid);//打印出消息队列的ID
30     system("ipcs -q");//通过ipcs -q查看系统中刚创建的消息
31     sleep(3);//系统休眠3秒
32
33     if((msgsnd(qid,&pmsg,len,0))<0)//向创建的消息队列发送消息
34     {
35         perror("msgsnd Error");
36         exit(0);
37     }
38
39     printf("successfully send a message to queue:%d\n",qid);//打印成功发送
40     sleep(2);//休眠2秒
41
42     len = msgrcv(qid,&pmsg,BUFSZ,0,0);//读取消息
43     if(len > 0)//读取消息大于0
44     {
45         pmsg.msg_buf[len] = '\0';//在最后添加字符串结束符,方便后续处理
46         printf("reading queue id:%05d\n",qid);//从哪个消息队列(id)读取的消息
47         printf("message type:%05ld\n",pmsg.msg_types);//消息类型
48         printf("message length:%d bytes\n",len);//消息大小
49         printf("message text:%s\n",pmsg.msg_buf);//消息内容
50     }
51     else if(len == 0)//消息队列中没有消息可读
52     {
53         printf("have no message from queue %ld\n",qid);
54     }
55     else//读取出错
56     {
57         perror("msgrcv Error");
58         exit(1);
59     }
60
61     system("ipcs -q");//再次查看系统中的消息队列
62     exit(0);
63 }
64


以下为FEDORA 21上的测试结果:

[bulleye@localhost IPC]$ ./msg
create queue:32769

--------- 消息队列 -----------
键        msqid      拥有者  权限     已用字节数 消息
0x00000000 0          bulleye    666        0            0
0x00000000 32769      bulleye    666        0            0

successfully send a message to queue:32769
reading queue id:32769
message type:02298
message length:20 bytes
message text:Hello!this is :2298

--------- 消息队列 -----------
键        msqid      拥有者  权限     已用字节数 消息
0x00000000 0          bulleye    666        0            0
0x00000000 32769      bulleye    666        0            0

[bulleye@localhost IPC]$
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ipc 消息队列