栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

【Linux】进程通信(消息队列Message Queue)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Linux】进程通信(消息队列Message Queue)

文章目录
      • (一)消息队列
        • (1)消息队列原理
        • (2)Linux系统下的两个宏定义:(其它系统未知)
      • (二)消息队列函数
        • (1)创建,访问一个消息队列
        • (2)添加消息到队列中
        • (3)从消息队列中获取消息
        • (4)消息队列的控制函数
      • (三)简单使用消息队列

(一)消息队列
  • 消息队列与有名管道相似
  • 消息队列不需要管道的打开和关闭管道的操作
  • 消息队列并未解决管道满时的阻塞问题
(1)消息队列原理
  • 一个进程向另一个进程发送一个数据块(含有类型)
  • 接收进程可以独立地接收不同类型的数据块
  • 可以避免有名管道的同步和阻塞问题(未满状态)
  • 可以查看紧急消息
  • 每个数据块都有一个最大的长度限制(超出限制,消息队列函数失败的原因)
  • 所有队列的所有数据块的总长度也有上限
(2)Linux系统下的两个宏定义:(其它系统未知)
  • 一条消息的最大长度:MSGMAX
  • 一个队列的最大长度:MSGMNB
(二)消息队列函数 (1)创建,访问一个消息队列

int msgget(key_t key, int msgflg);

  • key : 键值,通过同一个键值来访问同一个消息队列(特殊键值IPC_PRIVATE,当前进程可用,私有队列没啥用)
  • msgflg : 必须使用IPC_CREAT 和 | 按位或才能创建新的消息队列(没有则创建,已存在则忽略)
  • 返回值 :成功返回队列标识符(正整数),失败-1
(2)添加消息到队列中

int msgsnd(int msqid, const void* msg_ptr, size_t msg_sz, int msgflg);

  • msqid : msgget的返回的消息队列标识符
  • msg_ptr : 是指向准备发送消息(数据块struct my_message{};)的指针
    约束条件:
  • 消息队列的长度小于系统规定的上限
  • 必须以一个长整形long int 变量开始(作为接收函数区分类型的标准)
    建议创建一个结构体类型:
    struct my_message
    {
    long int message_type; //消息类型 > 0
    ...
    }
  • msg_sz : msg_ptr指向消息的长度(不包含类型的字节大小)
  • msgflg : 控制此消息队列达到系统限制(队满),要发生的事。

(IPC_NOWAIT|函数不发送消息并立即返回-1)

队满情况下:如果没有请求类型的消息可用,且未指定IPC_NOWAIT,在MSGFLG中,调用过程被阻塞(等待系统的消息队列中腾出空间),直到下列条件之一:

  • 所需类型的消息放置再队列中
  • 消息队列被系统删除,系统调用失败,错误号设置为EIDRM
  • 调用进程捕获一个信号。在这种情况下,系统调用失败将errno设置为EINTR。
  • 返回值:成功返回0,失败-1
(3)从消息队列中获取消息

int msgrcv(int msaid, void* msg_ptr, size_t msg_sz, long int mstype, int msgflg);

  • msqid : 是msgget返回的消息队列的标识符
  • msg_ptr : 是一个指向准备接收消息的指针(struct my_message{long int , …};)
  • msg_sz : 是接收消息的长度(不包括消息类型字节大小)
  • msgtype : 是一个长整数,可以实现简单形式的优先级(优先级消息队列)

注意:

  • msgtype为0,获取队列中第一个可用消息
  • 大于0,获取同种类型的第一条消息
  • 小于0,获取 小于或等于msgtype的绝对值的类型的第一条消息

接受类型使用场景:

  • 获取队列中每一个元素,msgtype = 0
  • 获取msgtype对应类型的第一条消息
  • 获取小于n类型的消息:msgtype = -n;
  • msgflg : 控制队列中没有相应类型的消息可以接收时的事件。设置IPC_NOWAIT,函数立即返回-1;若IPC_NOWAIT标记被清除,进程将会挂起等待相应类型消息到达;

  • 返回值:成功返回接收缓存区中的字节大小,消息被复制到msg_ptr指向的缓存空间中,删除消息队列中相应消息,失败返回-1

(4)消息队列的控制函数

int msgctl(int msqid, int command, struct msqid_ds* buff);

  • msqid : 时msgget返回的消息队列标识符
  • command : 3种操作方式如下
command说明
IPC_STAT把msqid_ds结构中数据设置为消息队列的当前关联值
IPC_SET若进程有足够权限,就把消息队列当前关联值设置成msqid_ds结构中给定的值
IPC_RMID删除消息队列
  • buf : struct msqid_ds类型的指针,结构体如下

struct msqid
{
uid_t msg_perm.uid;
uid_t msg_perm.gid;
mode_t msg_perm.mode;
}

(三)简单使用消息队列

a进程写入type = 1 data = "hello world"消息队列中,b进程获取该消息输出

  • msg.h
#include 
#include 
#include 
#include 

struct msgbuf
{
	long int type;	//消息类型
	char data[32];	//数据
};
  • a.c
#include "msg.h"

void SendMessage()
{
	//创建消息队列
	int msqid = msgget((key_t)8888, IPC_CREAT | 0600);
	if(msqid == -1)
	{
		perror("msgget err");
		return;
	}

	//向消息队列发送消息
	struct msgbuf buf;
	buf.type = 1;
	strcpy(buf.data, "hello world");
	
	if(msgsnd(msqid, &buf, 32, 0) == -1)
	{
		perror("msgsnd err");
		return;
	}
}


int main()
{
	SendMessage();
	return 0;
}
  • b.c
#include "msg.h"

void RecvMessage()
{
	//创建消息队列
	int msqid = msgget((key_t)8888, IPC_CREAT | 0600);
	if(msqid == -1)
	{
		perror("msgget err");
		return;
	}

	//从消息队列获取消息
	struct msgbuf buf;
	
	if(msgrcv(msqid, &buf, 32, 1, 0) == -1)
	{
		perror("msgsnd err");
		return;
	}
	printf("%sn", buf.data);

	sleep(2);
	//销毁消息队列
	if(msgctl(msqid, IPC_RMID, NULL) == -1)
	{
		perror("msgctl IPC_RMID err");
		return;
	}
}


int main()
{
	RecvMessage();
	return 0;
}

结果:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/599441.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号