当前位置: 首页 > article >正文

进程间通信——IPC机制(二)消息队列

目录

 前言

一、什么是消息队列

二、创建消息队列的函数 


 前言

        在之前我的博客中讲述了传统的进程间通信方式,即通过管道传输,信号辅助;

        本文主要讲述消息的通信方式,即通过消息队列,和共享文件进行传输数据,后面也会使用信号灯、同步互斥机制来控制传输顺序。

一、什么是消息队列

        消息队列就是在内核中创建一个队列,进程会将数据打包成结点,添加到队尾,进程也可以从队头读取结点,实现进程的通信(先进先出的通信)

         消息队列的特点:

  • 消息队列的消息有固定的格式(消息的类型+消息的正文)
  • 消息队列根据先进先出原则读取数据,同时可以指定消息的类型进行读取

  • 消息队列独立于进程

  • 使用消息队列传输数据时,只有当两个进程都结束,消息队列才会被释放

二、创建消息队列的函数 

         1、msgget():创建消息队列

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

int msgget(key_t key, int msgflg);
功能:通过key值,创建或打开一个key值对应的消息队列

参数:
参数1:
    key_t key: key值
参数2:
    int msgflg:
        IPC_CREAT:如果key值对应的消息队列不存在,则创建消息队列
        IPC_CREAT | 0664 :创建的同时指定权限,如果消息队列已经存在,则会忽略这个权限
        
返回值:
成功,返回消息队列的对应id     
失败,返回-1      

        2、msgsed():发送消息到消息队列中

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

int msgsnd(int msqid, const void *msgp, size_t msgsz , int msgflg);
功能:向消息队列中发送消息

参数:
参数1:
    int msqid:消息队列的id,指定进程要发送到哪个消息队列中
参数2:
    const void *msgp:指定要发送的消息的数据地址
        消息格式:----自定义
        struct msgbuf {
               long mtype;消息类型-------发送时,消息类型 > 0
               xxx mtext[xxx];消息的正文数据
           };
参数3:
     size_t msgsz:消息正文数据的大小, mtext大小
参数4:
    int msgflg:发送方式
        0:默认方式,当消息队列满了,msgsnd会阻塞等待
        IPC_NOWAIT:非阻塞方式,当消息队列满了,msgsnd 不会阻塞等待,直接结束当前函数,不发送
             
返回值:
成功,返回0
失败,返回-1

        3、msgrcv():从指定的消息队列中读取数据

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

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
功能:从指定的消息队列中读取消息

参数:
参数1:
    int msqid:要读取消息的消息队列id
参数2:
    void *msgp:指定要将读取的消息存储在哪个地址,注意,以什么类型写入消息队列,就以什么类型从消息队列中读取
        消息格式:----自定义
        struct msgbuf {
               long mtype;消息类型
               xxx mtext[xxx];消息的正文数据
           };        
参数3:
     size_t msgsz:消息正文大小,   mtext大小
参数4:
    long msgtyp:要读取的消息的类型
           msgtyp > 0 :读取消息队列中,指定  msgtyp 类型消息的第一条消息   
           msgtyp == 0  :读取消息队列中第一条消息
参数5:
     int msgflg:接收方式
         0:默认方式,当消息队列没有数据时,msgrcv会阻塞等待
         IPC_NOWAIT:非阻塞方式,当消息队列没有数据时,msgrcv 不会阻塞等待,直接结束当前函数,不接收

返回值:
    成功,返回0
    失败,返回-1 

        

        4、msgctl():控制消息队列的函数,可以实现删除,获取队列信息等等的功能

     IPC_NOWAIT:非阻塞方式,当消息队列没有数据时,msgrcv 不会阻塞等待,直接结束当前函数,不接收

返回值:
    成功,返回0
    失败,返回-1                                    

4、msgctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:控制消息队列,主要用于删除消息队列

参数:
参数1:
    int msqid:要控制操作的消息队列id
参数2:
    int cmd:控制命令
        IPC_STAT:获取消息队列属性,获取的属性值存储到 第三个参数 指针变量 对应的地址空间   
        IPC_SET:设置消息队列属性,把 第三个参数 指针变量对应空间的属性值 设置到消息队列中 
        IPC_RMID:删除消息队列, 第三个参数为 NULL
        
返回值:
成功,返回0
失败,返回-1   

        例如,现在我要实现1.c和2.c之间的通信,如下:

1.c

//用消息队列实现两个进程之间的通信
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MSG_SIZE 80
//定义消息队列的结点
struct my_msg {
	long int type;
	char buf[MSG_SIZE];
};

int main(void)
{
	int msgid;
	int ret;
	struct my_msg msg;
	//创建消息队列
	msgid = msgget((key_t)1235, 0666|IPC_CREAT);
	if (msgid == -1) {
		printf("msgget failed!\n");
		exit(1);//如果创建失败,结束进程
	}
	while(1){
		scanf("%ld",&(msg.type));	
		scanf("%s",msg.buf);
      	 // 传入0:如果消息队列满了,那么就阻塞
		ret = msgsnd(msgid, &msg, MSG_SIZE, 0);
		if (strcmp(msg.buf,"quit")==0) 
		{
			printf("msgsnd failed!\n");
			break;
		}
	}
	//删除队列
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

2.c

//接收消息队列的信息
#include<stdio.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<sys/msg.h>
struct my_msg
{
	long type;
	char buf[80];
};
int main(int argc, const char *argv[])
{
	//创建或者打开消息队列
	int msgid;
	msgid=msgget((key_t)1235,IPC_CREAT | 0664);
	if(msgid<0)
	{
		perror("msgget failed:");
		return -1;
	}
	//从消息队列中读取数据
	while(1)
	{
		struct my_msg my_data;
		int num;
		//输入队列下标获取对应数据
		scanf("%d",&num);
		//获取队列中的数据
		msgrcv(msgid,&my_data,sizeof(struct my_msg)-sizeof(long),num,0);
		printf("type=%ld,buf=%s \n",my_data.type,my_data.buf);
		if(strcmp(my_data.buf,"quit")==0)
		{
			break;
		}
	}
	//关闭消息队列
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}


http://www.kler.cn/a/287974.html

相关文章:

  • ollama+springboot ai+vue+elementUI整合
  • 对接阿里云实人认证
  • 【征稿倒计时!华南理工大学主办 | IEEE出版 | EI检索稳定】2024智能机器人与自动控制国际学术会议 (IRAC 2024)
  • 【数据库系列】 Spring Boot 集成 Neo4j 的详细介绍
  • WPF中如何使用区域导航
  • 深入探索离散 Hopfield 神经网络
  • 设计模式创建型模式之原型模式
  • Android TV的行添加和行中数据项添加
  • 3. 创建一个新的 Git 仓库
  • MySQL之数据库基础
  • SpringBoot项目集成支付宝
  • 2024.8.28 C++
  • 物联网之云平台架构
  • 详细解说:ansible自动化运维项目
  • python基础(16面试题附答案一)
  • 【随记】开源 AI(Open source AI)
  • read()和readlines()的区别
  • DReg-NeRF: Deep Registration for Neural Radiance Fields论文解读
  • Flask框架 完整实战案例 附代码解读 【3】
  • 【ag-grid】列宽设置不生效探索
  • 基于vue框架的超市管理系统y9992(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • Linux_kernel简介01
  • JavaEE 第21节 UDP数据报结构剖析
  • 【区块链 + 物联网】可信保密的海洋大数据分析平台 | FISCO BCOS应用案例
  • SpringAOPSpring事物管理
  • UE5蓝图 抽卡出货概率