进程间通信IPC-消息队列

什么是IPC对象?

在Linux下,IPC对象是指消息队列、共享内存、信号量,如果用户想要利用IPC对象进行进程间通信的话,首先需要为IPC对象申请对应的资源,即该对象的key值和id,key值可以理解为文件操作里面的文件路径名,而id号可以理解为文件操作里面的文件描述符。

Linux系统下的IPC资源

查看IPC资源: ipcs -a

在这里插入图片描述

删除IPC资源
删除消息队列:ipcrm -q key值或id值
删除共享内存:ipcrm -m key值或id值
删除信号量:ipcrm -s key值或id值

使用IPC对象,使用ftok申请key值

key_t ftok(const char *pathname, int proj_id);
函数功能:
为IPC对象获取一个key值
参数:
pathname----->一个合法的路径,常用"."当前路径
proj_id----->非0常数,常用10
返回值:
成功返回key值;失败返回-1
注意:
当使用ftok来申请key值时,如果pathname和proj_id值和上一次的使用ftok时的值都相同时,两次获得的key值都相同;只要有pathname或者proj_id有一个不同时,获得的key值就不同。

IPC-消息队列

  • 管道通信和消息队列之间的区别?

管道通信:不能读取指定的数据,只要管道中有数据,就一定要读出来,操作函数是open/read/write;
消息队列:消息队列是带有特殊标识的特殊管道,可以读取指定的数据,不符合类型就不读取,操作函数是msgget/msgsnd/msgrcv;

  • 消息队列机制?

进程1往消息队列里发送消息:“类型编号”+“数据正文”
进程2从消息队列里读取消息,只用提供相应的数据编号就可以读取到指定的数据。
作用范围:Linux下任意两个进程

  • 消息格式?
strcut msgbuf
{
	long type;	//消息的编号
	char buf[n];	//消息的正文部分,大小n自行设置
}

消息队列操作函数

int msgget(key_t key, int msgflg);
函数功能:
得到消息队列的id号
函数参数:
key----->消息队列的key值
msgflg----->IPC | 0666 (如果不存在就创建,并给读写权限,Linux下IPC资源的访问权限一般为读和写,没有执行权限)
返回值:成功返回消息队列的id号;失败返回-1。

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
函数功能:
往消息队列里写入数据
参数:
msqid----->消息队列id号
msgp----->要写入的消息的地址
msgsz----->消息的数据正文的大小(不是整个消息结构体的大小)
msgflg----->一般属性,默认为0
返回值:成功返回0;失败返回-1。

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
函数功能:
在消息队列里读取指定的消息
参数:
msqid----->消息队列的id值
msgp----->接受消息的指针
msgsz----->接受消息的字节大小
msgtyp----->消息队列里指定的消息编号
msgflg----->一般属性,默认为0
返回值:成功返回读取到的字节数;失败返回-1。

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数功能:
操作消息队列的状态
参数:
msgid----->消息队列的id值
cmd----->IPC_STAT(获取消息队列的状态,获取到第三个参数里)或 IPC_RMID(删除消息队列,第三个参数设置为NULL)
buf----->将获取到的消息队列的状态存储在buf里
返回值:成功返回0;失败返回-1。

例子:进程2可以不断地发送数据给进程1,进程1将数据打印出来。

//进程2:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

//定义一个记录消息队列里的消息的结构体
struct msg
{
    long type;
    char buf[1024];
};

int main(int argc, char const *argv[])
{
    key_t msgq_key;  //ipc资源键值
    msgq_key = ftok(".", 10);  //获取键值
    printf("key = %x\n", msgq_key);

    int msgq_id = msgget(msgq_key, IPC_CREAT|0666);  //创建消息队列并获得ipc资源id
    if(-1 == msgq_id)   //获取id失败返回-1
    {
        perror("msgget");
        exit(1);
    }
    else
        printf("msdid=%d\n", msgq_id);

    struct msg msg_buf;     //消息的结构体
    bzero(&msg_buf, sizeof(msg_buf));
    msg_buf.type = 2;   //消息类型
    strcpy(msg_buf.buf, "Are you happy?");  //消息内容

    //向消息队列一直写入信息
    while(1)
    {
        scanf("%[^\n]", msg_buf.buf);   //读取用户写入到消息队列里的数据
        while(getchar() != '\n');   //清空缓冲区

        //向这个消息队列里写入数据
        if(msgsnd(msgq_id, &msg_buf, strlen(msg_buf.buf), 0) == -1)
        {
            printf("msgsnd error");
            exit(2);
        }
        memset(msg_buf.buf, 0, sizeof(msg_buf));    //清空消息buf

    }

    return 0;
}

//进程1:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

//定义一个记录消息队列里的消息的结构体
struct msg
{
    long type;
    char buf[1024];
};

int main(int argc, char const *argv[])
{
    key_t msgq_key;  //ipc资源键值
    msgq_key = ftok(".", 10);  //获取键值
    printf("key = %x\n", msgq_key);

    int msgq_id = msgget(msgq_key, IPC_CREAT|0666);  //创建消息队列并获得ipc资源id
    if(-1 == msgq_id)   //获取id失败返回-1
    {
        perror("msgget");
        exit(1);
    }
    else
        printf("msdid=%d\n", msgq_id);

    struct msg msg_buf;     //消息的结构体
    bzero(&msg_buf, sizeof(msg_buf));

    int ret = 0;    //ret代表从消息队列里读取到的字节数
    while(1)
    {
        //向这个消息队列里读出数据
        ret = msgrcv(msgq_id, &msg_buf, sizeof(msg_buf.buf), 2, 0);
        if(ret > 0)
        {
            printf("from msq:%s\n", msg_buf.buf); 
        }

        memset(msg_buf.buf, 0, sizeof(msg_buf.buf));
    }

    return 0;
}

在这里插入图片描述
结果分析:进程2将消息消息的编号设置为了2,进程一通过msgsrc接收消息队列里的消息编号为2的消息。
利用ipcs -a查看ipc资源:在这里插入图片描述
把进程1终止,在进程2里继续发送2条消息,查看到消息队列里的消息数量更新到了2,说明进程1终止后,进程2发送的消息还留在消息队列里:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值