Linux IPC 之消息队列

5 篇文章 0 订阅
3 篇文章 0 订阅

今天学习了一下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]$ 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值