LINUX进程间通信(IPC)--消息队列

一、消息队列

消息队列是消息的链表,存放在内核中并由消息队列标识符(msqid)表示。

消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接受者接受的数据块可以有不同的类型。

二、特点

  • 消息队列独立于发送与接受进程。进程终止时,消息队列及其内容不会被删除,需要调用接口删除或使用命令删除
  • 消息队列是面向记录的,其中的消息具有特定的格式及优先级,克服了管道只能承载无格式字节流的缺点
  • 消息队列可以双向通信消息队列可实现消息的随机查询,也可按照消息类型读取

三、消息队列函数

头文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

1.msgget

功能:创建和访问一个消息队列
原型:

int msgget(key_t key, int msgflag);

参数
key:某个消息队列的名字,键值,用ftok()产生
msgflag:有两个选项IPC_CREAT和IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。
返回值:成功返回一个非负整数,即消息队列的标识码,失败返回-1

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
//eg:
key_t key; //可通过ls -i 查询
key = ftok(".",'z');     //"."当前路径 任意字母或数字
printf("key = %x\n",key);

pathname为已经存在的文件名,“.”表示当前目录;id为子序号,值范围只有8bit(0-255)
调用成功返回一个key值,用于创建消息队列,如果失败,返回-1(可通过ls -i 查询)

2.msgsnd

功能:把一条消息添加到消息队列中
原型

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数

msgid:由msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息(注意是指针)
msgze:msgp指向的消息的长度(不包括消息类型的long int长整型)
msgflg:默认为0
返回值:成功返回0,失败返回-1

消息结构一方面必须小于系统规定的上限,另一方面必须以一个long int长整型开始,接受者以此来确定消息的类型

struct msgbuf
{
     long mtye; //用于确定消息类型
     char mtext[1];
};
//eg:main中定义一个发送信号的赋值
struct msgbuf sendbuf = {888,"hello world"};
//将mtye 定义为888类型,接收消息msgrcv要填写相应的类型

3.msgrcv

功能:是从一个消息队列接受消息
原型:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

参数:与msgsnd相同
long typ:填写与定义结构体相对于的类型,用于匹配接收相应的信息
函数msgrcv在读取消息队列时,type参数有下面几种情况
type == 0,返回队列中的第一个消息;
type > 0,返回队列中消息类型为 type 的第一个消息;
type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。
返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1

4.msgctl

功能:消息队列的控制函数
原型

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

参数
msqid:由msgget函数返回的消息队列标识码
cmd:有三个可选的值,在此我们使用IPC_RMID

  • IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
  • IPC_SET 在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
  • IPC_RMID 删除消息队列

*buf:一般写为NULL
返回值
成功返回0,失败返回-1

删除消息队列

消息队列可以通过msgctl(msgid,IPC_RMID,NULL)删除
同时还有两个指令
ipcs:显示IPC资源
ipcrm:手动删除IPC资源
在这里插入图片描述

四、demo消息队列的信息传输

进程A B的信息传递,B添加一个数据块(类型888)到消息队列,A从消息队列上获取B添加的数据块。A获取后也添加一个数据块(类型988)到消息队列,B再从消息队列上获取改数据块。完成AB间信息交互。

msg_A.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
// int msgget(key_t key, int msgflg);
//int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
//int msgsnd(int msqid, const void *ptr, size_t size, int flag);
struct msgbuf
{
        long ntype;
        char mtext[128];
};
int main()
{
        key_t key;
        key = ftok(".",'z'); //产生键值key,两进程保证键值相同以确定同一消息队列
        printf("key = %x\n",key);

        struct msgbuf readbuf; //定义一个用于获取(相当于接收)的readbuf数据块

        int msgid = msgget(key,IPC_CREAT|0777);  //创建或打开一个消息队列
        if(msgid == -1) //如果创建失败
        {
                printf("creat  faile");
        }
        
        //从消息队列上接收数据块到readbuf,888为相对应的类型
        msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),888,0);//readbuf此时内容为空,sizeof
        printf("read from send:%s\n",readbuf.mtext);//打印获取的消息
		
		//创建一个用于添加(相当于发送)的sendbuf数据块,并定义数据类型为988
        struct msgbuf sendbuf = {988,"thank you over"};
        
        //将数据块添加到消息队列    根据内容大小strlen
        msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);
        
        msgctl(msgid,IPC_RMID,NULL);//删除消息队列
        return 0;
}

msg_B.c

//头文件省略

struct msgbuf
{
        long ntype;
        char mtext[128];

};
int main()
{
        key_t key;
        key = ftok(".",'z');
        printf("key = %x\n",key);
        
        //创建一个用于添加(相当于发送)的sendbuf数据块,并定义数据类型为888
        struct msgbuf sendbuf = {888,"hello world"};
        struct msgbuf readbuf;  //定义一个用于获取(相当于接收)的readbuf数据块
        int msgid = msgget(key,IPC_CREAT|0777);  // //创建或打开一个消息队列
        if(msgid == -1)
        {
                printf("creat  faile");
        }
		//将数据块添加到消息队列 strlen
        msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);//strlen
		
		//从消息队列上接收数据块到readbuf,888为相对应的类型
        msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),988,0); //sizeof

        printf("read from get :%s\n",readbuf.mtext);
		//打印获取的内容
        return 0;
}
~                        

进程A 与 进程B 同时运行完成信息交互
A获取到B添加到消息队列的hello world
B获取到A添加到消息队列的thank you over

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值