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标志位,则当队列中无符合条件的消息时,函数出错返回;否则,直到出现满足条件的消息为止,然后函数读取消息返回。
下面是一段简单的测试代码:
以下为FEDORA 21上的测试结果:
消息队列可能是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通道入侵相关命令整理
- Linux IPC命令的用法详解
- 基于条件变量的消息队列 说明介绍
- Linux进程通信(IPC)方式简介
- PHP+memcache实现消息队列案例分享
- Linux进程间通信(IPC)方式总结
- Android 跨进程通信基础
- IBM WebSphere MQ介绍安装以及配置服务详解
- RocketMQ与Kafka对比(18项差异)评价版
- ipc$ 安全
- IPC(进程间通信)几种常用的方法
- 共享内存的进程间通信库
- 详尽解析IPC$的******方法
- Messenger实现Android IPC
- Android深入浅出之Binder机制(一)
- Android深入浅出之Binder机制(二)
- Android Binder设计与实现 - 设计篇(一)
- Android Binder设计与实现 - 设计篇(二)
- Android Binder IPC分析