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

Linux 基本语句_13_消息队列

概念:

不同进程能通过消息队列来进行通信,不同进程也能获取或发送特定类型的消息,即选择性的收发消息。

一般一个程序采取子进程发消息,父进程收消息的模式

常用函数功能:

fork(); // 创建子进程

struct msgbuf{ // 数据协议
    long mtype; // 数据类型,由用户自己定义
    char buf[N]; // 数据部分
};

key = ftok(“.”, ‘a’) // 创建键值

第一个参数是路径名,通常是一个已经存在的文件或目录的路径名。在这个例子中,.表示当前目录,也就是代码所在的目录。
第二个参数是一个由用户自定义的字符,用于生成键值。在这里,它是字符 ‘a’。

这个键值的作用即标识一个消息队列,通过键值识别具体的某条消息队列


代码:

SndTp1RcvTp2.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>
#include <signal.h>

#define N 128
#define SIZE sizeof(struct msgbuf) - sizeof(long)
#define TYPE1 100
#define TYPE2 200

struct msgbuf{
	long mtype;
	char buf[N];
};

int main(){
	key_t  key;
	if((key = ftok(".", 'a')) < 0){ // 创建键值 
		perror("ftok error");
		return -1;
	}
	
	int msqid;
	struct msgbuf msg_snd, msg_rcv; // 发送端接收端
	if((msqid = msgget(key, IPC_CREAT|IPC_EXCL|0664)) < 0){ // 创建消息队列 存在则报错 出现错误返回-1 
		if(errno != EEXIST){ // 若消息不存在 
			perror("msgget error");
			return -1; 
		}
		else{ // 则消息队列存在 直接打开 
			msqid = msgget(key, 0664); 
		} 
	} 
	
	pid_t pid;
	
	pid = fork(); // 创建子进程
	
	if(pid < 0){
		perror("fork error");
		return -1;
	} 
	else if(pid == 0){ // 若是子进程 
		while(1){
			msg_snd.mtype = TYPE1; // 标识信息的符号
			fgets(msg_snd.buf, N, stdin); // 标准输入 读取用户输入
			msg_snd.buf[strlen(msg_snd.buf) - 1] = '\0'; // 方便读取
			
			msgsnd(msqid, &msg_snd, SIZE, 0); // 消息无法发送则阻塞直到可发送为止 
			
			if(strncmp(msg_snd.buf, "quit", 4) == 0){ // 查看用户输入若为quit 则结束父进程 子进程自我结束 
				kill(getppid(), SIGKILL);
				break;
			} 
			
		} 
	}
	else{ // 父进程 
	    while(1){
		
		    msgrcv(msqid, &msg_rcv, SIZE, TYPE2, 0); // 只接收 TYPE2 直到等到有符合条件的消息为止 
		
		    if(strncmp(msg_rcv.buf, "quit", 4) == 0){
			    kill(pid, SIGKILL);
			    msgctl(msqid, IPC_RMID, NULL); // 删除消息队列 
			    break;
		    }
		
		    printf("msg_b:%s\n", msg_rcv.buf);
	    }
	}	
	return 0;
}

SndTp2RcvTp1.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>
#include <signal.h>

#define N 128
#define SIZE sizeof(struct msgbuf) - sizeof(long)
#define TYPE1 100
#define TYPE2 200

struct msgbuf{
	long mtype;
	char buf[N];
};

int main(){
	key_t  key;
	if((key = ftok(".", 'a')) < 0){ // 创建键值 
		perror("ftok error");
		return -1;
	}
	
	int msqid;
	struct msgbuf msg_snd, msg_rcv; // 发送端接收端
	if((msqid = msgget(key, IPC_CREAT|IPC_EXCL|0664)) < 0){ // 创建消息队列 存在则报错 出现错误返回-1 
		if(errno != EEXIST){ // 若消息不存在 
			perror("msgget error");
			return -1; 
		}
		else{ // 则消息队列存在 直接打开 
			msqid = msgget(key, 0664); 
		} 
	} 
	
	pid_t pid;
	
	pid = fork(); // 创建子进程
	
	if(pid < 0){
		perror("fork error");
		return -1;
	} 
	else if(pid == 0){ // 若是子进程  发送方 
		while(1){
			msg_snd.mtype = TYPE2; // 标识信息的符号
			fgets(msg_snd.buf, N, stdin); // 标准输入 读取用户输入
			msg_snd.buf[strlen(msg_snd.buf) - 1] = '\0'; // 方便读取
			
			msgsnd(msqid, &msg_snd, SIZE, 0); // 消息无法发送则阻塞直到可发送为止 
			
			if(strncmp(msg_snd.buf, "quit", 4) == 0){ // 查看用户输入若为quit 则结束父进程 子进程自我结束 
				kill(getppid(), SIGKILL);
				break;
			} 
			
		} 
	}
	else{ // 父进程  接受方 
	    while(1){
	        msgrcv(msqid, &msg_rcv, SIZE, TYPE1, 0); // 只接收 TYPE1 直到等到有符合条件的消息为止 
		
		    if(strncmp(msg_rcv.buf, "quit", 4) == 0){
			    kill(pid, SIGKILL);
			    msgctl(msqid, IPC_RMID, NULL); // 删除消息队列 
			    break; 
		    }
		    
		    printf("msg_a:%s\n", msg_rcv.buf);
		}
	}
	 
	return 0;
}

俩个程序各开一个子进程,父进程。子进程负责发送信息,父进程负责接收信息,最终能实现在不同终端通讯,发送quit终止通讯

效果:

在这里插入图片描述


http://www.kler.cn/news/150231.html

相关文章:

  • Arduino驱动SHT4x温湿度传感器(温湿度传感器)
  • Python内置函数与标准库函数的详细解读
  • Kubernetes - Pod 拉取镜像报错 ImagePullBackOff
  • 【从浅识到熟知Linux】基本指令之rmdir和rm
  • leetcode 15. 三数之和
  • 如何快速生成项目目录结构树?
  • flink源码分析之功能组件(四)-slotpool组件II
  • 基于minio,上传sql文件后,使用通用查询接口查询并返回
  • 数据结构-02-链表
  • 对二分搜索的理解 Go语言版
  • 从 Elasticsearch 到 SelectDB,观测云实现日志存储与分析的 10 倍性价比提升
  • 智能化质量控制,三坐标尺寸SPC管理系统引领制造新潮流!
  • sqli-labs靶场详解(less32-less37)
  • 什么是主机安全,有什么作用?
  • Android Studio Giraffe-2022.3.1-Patch-3安装注意事项
  • @Value和@ConfigurationProperties的区别,以及@ConfigurationProperties的配置依赖
  • 详解前后端交互时PO,DTO,VO模型类的应用场景
  • [论文阅读]CT3D——逐通道transformer改进3D目标检测
  • RK3568平台开发系列讲解(Linux系统篇)通过OF函数获取设备树节点实验
  • 云时空社会化商业 ERP 系统 service SQL 注入漏洞复现
  • mySQL踩坑记录
  • 【科技素养】蓝桥杯STEMA 科技素养组模拟练习试卷12
  • 从零构建属于自己的GPT系列1:文本数据预处理、文本数据tokenizer、逐行代码解读
  • SparkSQL远程调试(IDEA)
  • 深入了解Jackson库中的ObjectMapper:Java对象的序列化和反序列化
  • qt 简单了解QHBoxLayout QVBoxLayout QFormLayout水平,垂直,表单布局管理器.
  • BUUCTF刷题之路-pwn-ciscn_2019_n_81
  • Elasticsearch 聚合查询(Aggregation)详解
  • 虚拟机指定开放数据库3306端口
  • Golang开发之------ Beego框架