消息队列的删除在哪个进程进行的_进程通信之消息队列

178288793748b9a72cfc32e3e8949418.png

之前介绍了进程间通信的PIPE通信、FIFO通信和共享内存,三种通信方式各有其适用范围。

今天介绍第四种进程通信方式—消息队列。

消息队列的概念

消息队列从字面理解就是消息组成的列表。进程能够从消息队列添加消息和读取消息。

乍一看消息队列类似于FIFO通信,但消息队列能够实现消息的随机查询,有些读者会疑惑这是什么意思呢?

FIFO中的信息必须按照信息的先后顺序进行读取,而消息队列能够指定读取某条消息,即不必按照顺序读取消息。

另外,进程通过消息队列添加和读取的消息也保存在linux内核中,由“队列ID”进行标识。

消息队列的实现步骤

消息队列的实现较为简单,分为以下步骤:

(1)创建并打开消息队列。通过函数msgget()创建并打开消息队列。

(2)添加消息。通过函数msgsnd()函数将进程的消息添加到消息队列中。

(3)读取消息。通过函数msfrcv()函数把消息从消息队列读取到进程中。

NOTE:在创建消息队列时,需要利用ftok函数将一条已存在的路径和一个整数转换成类型为key_t的键值,这是由于msgget()函数需要利用ftok的返回值生成消息队列的ID。

消息队列的代码实现

下面是共享内存的代码实现(在linux环境下编译通过):

发送进程的代码实现:

//发送进程
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_BUFFER_LEN 1024

//定义消息结构体
struct message
{
	long msg_type;
	char msg_text[MAX_BUFFER_LEN];
};

int main()
{
	int msg_id;
	key_t key;
	struct message msg;
	
	key = ftok(".", 'a');//利用ftok函数将当前目录与'a'共同转化为key_t类型的键值
	if(key == -1)
	{
		perror("ftok");
		exit(1);
	}

	msg_id = msgget(key, IPC_CREAT|0666);//创建消息队列,并设置文件权限掩码0666
	if(msg_id == -1)
	{
		perror("creat msg");
		exit(1);
	}
	else
	{
		printf("the message queue ID is %dn", msg_id);
	}
	
	while(1)
	{
		printf("enter some message to the queus:");
		if(fgets(msg.msg_text, MAX_BUFFER_LEN, stdin) == NULL)
		{
			puts("no message");
			exit(1);
		}
		msg.msg_type = getpid();
		if(msgsnd(msg_id, &msg, strlen(msg.msg_text), 0) == -1)//添加消息到消息队列
		{
			perror("message posted.n");
			exit(1);
		}
		if(strncmp(msg.msg_text, "quit", 4) == 0)//如果接收的消息为quit,则退出接收进程
		{
			break;
		}
	}

	exit(0);//发送进程正常结束
	return 0;
}

接收进程的代码实现:

//接收进程
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#define MAX_BUFFER_LEN 1024 

//定义消息的结构体
struct message
{
	long msg_type;
	char msg_text[MAX_BUFFER_LEN];

};

int main()
{
	int msg_id;
	int key;
	struct message msg;
	
	key = ftok(".", 'a');//利用ftok函数将当前目录与'a'共同转化为key_t类型的键值
	if(key == -1)
	{
		perror("creat key");
		exit(1);
	}

	msg_id = msgget(key, IPC_CREAT|0666);//创建消息队列,并设置文件权限掩码0666
	if(msg_id == -1)
	{
		perror("get the message queue");
		exit(1);
	}
	else
	{
		printf("receive message ID is %dn", msg_id);
	}

	while(1)
	{
		memset(msg.msg_text, 0, MAX_BUFFER_LEN);//将消息队列清空
		if(msgrcv(msg_id, &msg, MAX_BUFFER_LEN, 0, 0) == -1)//接收进程从消息队列读取消息
		{
			perror("receive mess, error");
			exit(1);
		}
		else
		{
			printf("the message is %sn", msg.msg_text);
		}

		if(strncmp(msg.msg_text, "quit", 4) == 0)//如果接收的消息为quit,则退出接收进程
		{
			break;
		}
	}
	
	if(msgctl(msg_id, IPC_RMID, NULL) < 0)//IPC_RMID为从进程中删除消息队列
	{
		perror("msgctl");
		exit(1);
	}
	exit(0);//接收进程正常结束
	return 0;
}

Note:接收进程和发送进程均利用msgget函数创建消息队列,由于使用的消息队列的键值一致,所以返回的消息队列ID也是一样的,从而实现进程间消息传递。

下图是运行结果:

d33afa25c855f81b18bb820a06936ece.png

Note:在两个终端中分别运行接收进程和发送进程

总结

消息队列是进程间通信的一种常用方式,其广泛应用于实际项目中多进程的通信,感兴趣的读者可以自己在电脑上尝试实现消息队列通信。

当然,进程间的通信方式还有socket、信号和信号量。关于socke的通信原理还在学习中,后续将在公众号上更新。关于信号和信号量将会在线程的同步与互斥中介绍。

276681ac136c4b6836746cd03e0f32a3.png

ps: 欢迎关注我的公众号[酷酷的coder],分享转行菜鸟程序员成长过程汇总的烦恼和反思.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值