linux下的消息队列

1,概念:

消息队列的最佳定义是:内核地址空间中的内部链表。消息可以顺序地发送到队列中,并以几种不同的方式从队列中获取。当然,每个消息队列都是由 IPC 标识符所唯一标识的。

2,msgget()

msgget ( ) 的第一个变元是关键字的值 ( 可以调用 ftok ( ) 的返回值 ) 。这个关键字的值将被拿来与内核中其他消息队列的现有关键字值相比较。比较之后,打开或者访问操作依赖于 msgflg 变元的内容。

• IPC_CREAT — 如果在内核中不存在该队列,则创建它。

• IPC_EXCL — 当与 IPC_CREAT 一起使用时,如果队列早已存在则将出错。

如果只使用了 IPC_CREAT, msgget ( ) 或者返回新创建消息队列的消息队列标识符,或者会返回现有的具有同一个关键字值的队列的标识符

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
int msgget(key_t  key,int msgflag)
--------- 消息队列 -----------
键        msqid      拥有者  权限     已用字节数 消息      
0xffffffff 0          addia      666        0            0           
0x61091e8d 32769      addia      666        0            0    

#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>

int main()
{
	int qid;
	key_t key;
	key =111;
	qid=msgget(key,IPC_CREAT|0666);//创建一个消息队列
	if(qid<0)
	{
		perror("msgget error");
		exit(1);
	}
	printf("creat  queue id :%d\n",qid);//输出消息队列的id
	system("ipcs -q");//查看系统的ipc
	exit(0);
}

addia@addia-Lenovo-B470:~/演示代码$ ./msgget
creat  queue id :65538
--------- 消息队列 -----------
键        msqid      拥有者  权限     已用字节数 消息      
0xffffffff 0          addia      666        0            0           
0x61091e8d 32769      addia      666        0            0           
0x0000006f 65538      addia      666        0            0           
2,msgctl()

#include <sys/msg.h>
int msgctl( int msqid, int cmd , struct msqid_ds *buf );

cmd 参数详解

cmd

     

IPC_STAT

  取队列的 msqid_ds 结构,将它存放在 buf 所指向的结构中(需要 buf 参数)

IPC_SET

使用 buf 所指向结构中的值对当前队列的相关结构成员赋值,其中包括:msg_perm.uid  msg_perm.gid  msg_perm.mode 以及 msg_perm.cuid 。该命令只能由具有以下条件的进程执行:进程有效用户 ID 等于 msg_perm.cuid msg_perm.uid 超级用户进程。其中只有超级用户才可以增加队列的 msg_qbytes的值

IPC_RMID

删除队列,并清除队列中的所有消息。此操作会影响后续进程对这个队列的相关操作。该命令只能由具有以下条件的进程执行。进程有效用户 ID 等于msg_perm.cuid  msg_perm.uid ,超级用户进程



buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员:

struct msgid_ds
{
    uid_t shm_perm.uid;
    uid_t shm_perm.gid;
    mode_t shm_perm.mode;
};
成功时返回0,失败时返回-1 .
3,msgrcv()
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);

msgtype可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。
msgflg用于控制当队列中没有相应类型的消息可以接收时将发生的事情。
调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1 .
4,msgsnd()
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);

msgid是由msgget函数返回的消息队列标识符。
msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以 一个长整型成员变量开始的结构体接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样:

struct my_message{
    long int message_type;
    /* The data you wish to transfer*/
};
msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。
msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。
如果调用成功 ,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>

struct msg_buf
    {
        int mtype;
        char data[255];
    };
 
int main()
{
        key_t key;
        int msgid;
        int ret;
        struct msg_buf msgbuf;
 
        key=ftok(".",'a');
        printf("key =[%x]\n",key);
        msgid=msgget(key,IPC_CREAT|0666); /*通过文件对应*/

        if(msgid==-1)
        {
                printf("create error\n");
                return -1;
        }
 
        msgbuf.mtype = getpid();
        strcpy(msgbuf.data,"test haha");
        ret=msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);
        if(ret==-1)
        {
                printf("send message err\n");
                return -1;
        }
 
        memset(&msgbuf,0,sizeof(msgbuf));
        ret=msgrcv(msgid,&msgbuf,sizeof(msgbuf.data),getpid(),IPC_NOWAIT);
        if(ret==-1)
        {
                printf("recv message err\n");
                return -1;
        }
        printf("recv msg =[%s]\n",msgbuf.data);
 
}
addia@addia-Lenovo-B470:~/演示代码$ ./msg
key =[61091e8d]
recv msg =[test haha]

消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。在命名管道中,发送数据用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们对每个数据都有一个最大长度的限制。
与命名管道相比,消息队列的优势在于,1、消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值