Linux---进程通信(五)---IPC通信之消息队列

系列文章目录

文章一: Linux—进程通信(一)—进程通信概述
文章二: Linux—进程通信(二)—管道
文章三: Linux—进程通信(三)—信号通信
文章四: Linux—进程通信(四)—IPC通信之共享内存
文章五: Linux—进程通信(五)—IPC通信之消息队列
文章六: Linux—进程通信(六)—IPC通信之信号灯



前言

本文主要讲解IPC通信对象中的消息队列


一、消息队列

1.什么是消息队列?

消息队列是IPC通信的一个对象,存在于内核空间。消息队列的特别在于它是一个链式队列,即数据结构中的链表队列。

它本质上还是一个队列,因此读取了消息队列的内容后,该内容会从消息队列中删除。

2.消息队列的内容

一个消息队列包含下面的内容:

1.data:数据
2.length:数据长度
3.type:数据的类型
4.指针:链表的结点

3.消息队列的函数和文件I/O对比

文件I/O消息队列
openmsgget
readmsgrcv
writemsgsnd
closemsgctl

二、消息队列的使用

1.消息队列函数

创建消息队列

函数原型:

int msgget(key_t key,int flag);

所需头文件:

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

函数功能:

在内核空间中创建消息队列

函数参数:

1.key:和消息队列的key值
2.flag:消息队列的权限

函数返回值:

1.成功返回消息队列的ID,即消息队列的“文件描述符”
2.失败后返回-1

例子1:创建消息队列

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
int main()
{
	int msgid;
	msgid=shmget(IPC_PRIVATE,128,0777);
	if(msgid<0)
	{
		printf("create message queue failure\n");
		return -1;
	}
	printf("create message queue success shmid=%d\n",msgid);
	system("ipcs -q");
	return 0;
}

执行结果:
在这里插入图片描述

删除消息队列的函数

函数原型:

int msgctl(int msqid,int cmd,struct msqid_ds *buf);

所需头文件:

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

函数功能:

将内核空间中的消息队列删除,释放空间

函数参数:

1.msqid:消息队列的ID
2.cmd:
	(1)IPC_STAT:读取该消息队列的属性,并将其保存到buf指向的缓存区
	(2)IPC_SET:设置消息队列的属性,这个值取自buf
	(3)IPC_RMID:从系统中删除消息队列

函数返回值:

1.成功返回0
2.失败返回-1

例子2:应用msgctl函数

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
int main()
{
	int msgid;
	msgid=shmget(IPC_PRIVATE,128,0777);
	if(msgid<0)
	{
		printf("create message queue failure\n");
		return -1;
	}
	printf("create message queue success shmid=%d\n",msgid);
	system("ipcs -q");


	msgctl(msgid,IPC_RMID,NULL);
	system("ipcs -q");
	return 0;
}

消息队列的发送函数

函数原型:

int msgsnd(int msqid,const void *msgp,size_t size,int flag);

所需头文件:

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

函数功能:

向消息队列中写入信息。

函数参数:

1.msqid:消息队列的ID
2.msgp:指向消息的指针,常用的消息结构如下:
	struct msgbuf
	{
		long mtypes;    //消息类型
		char mtext[N]   //消息正文
	};
3.size:发送消息的正文的字节数
4.flag:
	(1)IPC_NOWAIT:消息没有发送完成函数也会立即返回
	(2)0:直到消息发送完成函数才返回,阻塞

函数返回值:

1.成功返回0
2.失败返回-1

消息队列的接收函数

函数原型:

int msgrcv(int msqid,void *msgp,size_t size,long msgtype,int flag);

所需头文件:

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

函数功能:

从消息队列中接收数据。

函数参数:

1.msqid:消息队列的ID
2.msgp:接收消息的指针,指向接收消息的缓存区。
	常用的消息结构如下:
	struct msgbuf
	{
		long mtypes;    //消息类型
		char mtext[N]   //消息正文
	};
3.size:要接收消息的字节数
4.msgtype:
	(1)0:接收消息队列的第一个消息。
	(2)大于0:接收消息队列中第一个类型值为msgtype的消息。
	(3)小于0:接收消息队列中类型值不大于msgtype的绝对值且类型值又最小的消息。
5.flag:
	(1)IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。
	(2)0:若无消息会一直阻塞

函数返回值:

1.成功返回接收到的消息的长度。
2.失败返回-1。

例子3:消息队列的读写函数实例

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
struct msgbuf
{
	long type;
	char voltage[124];
	char ID[4];
};
int main()
{
	int msgid;
	int readret;
	struct msgbuf sendbuf,recvbuf;
	msgid=shmget(IPC_PRIVATE,128,0777);
	if(msgid<0)
	{
		printf("create message queue failure\n");
		return -1;
	}
	printf("create message queue success shmid=%d\n",msgid);
	system("ipcs -q");

	sandbuf.type=100;
	printf("please input message:\n");
	fgets(sendbuf.voltage,124,stdin);

	msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);

	memset(recvbuf.voltage,0,124);
	readret=msgrcv(msgid,(void *)&recvbuf,124,100,0);
	printf("recv:%s\n",recvbuf.voltage);


	msgctl(msgid,IPC_RMID,NULL);
	system("ipcs -q");
	return 0;
}

执行结果:

在键盘中输入一段字符,接着会打印出一样的字符。

三、基于消息队列的无亲缘关系进程间通信

进程1用来发送数据
进程1的C语言代码:

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
struct msgbuf
{
	long type;
	char voltage[124];
	char ID[4];
};
int main()
{
	int msgid;
	int readret;
	int key;
	struct msgbuf sendbuf,recvbuf;
	key=ftok("./a.c","a");
	if(key<0)
	{
		printf("create key failure\n");
		return -2;
	}
	msgid=shmget(key,128,IPC_CREAT|0777);
	if(msgid<0)
	{
		printf("create message queue failure\n");
		return -1;
	}
	printf("create message queue success shmid=%d\n",msgid);
	system("ipcs -q");

	sandbuf.type=100;
	while(1)
	{
		memset(sendbuf.voltage,0,124);
		printf("please input message:\n");
		fgets(sendbuf.voltage,124,stdin);
		msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
	}

	msgctl(msgid,IPC_RMID,NULL);
	system("ipcs -q");
	return 0;
}

进程2用来接收数据
进程2的C语言代码:

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
struct msgbuf
{
	long type;
	char voltage[124];
	char ID[4];
};
int main()
{
	int msgid;
	int readret;
	int key;
	struct msgbuf sendbuf,recvbuf;
	key=ftok("./a.c","a");
	if(key<0)
	{
		printf("create key failure\n");
		return -2;
	}
	msgid=shmget(key,128,IPC_CREAT|0777);
	if(msgid<0)
	{
		printf("create message queue failure\n");
		return -1;
	}
	printf("create message queue success shmid=%d\n",msgid);
	system("ipcs -q");

	while(1)
	{
		memset(recvbuf.voltage,0,124);
		readret=msgrcv(msgid,(void *)&recvbuf,124,100,0);
		printf("recv:%s\n",recvbuf.voltage);
	}

	msgctl(msgid,IPC_RMID,NULL);
	system("ipcs -q");
	return 0;
}

执行结果:
进程1发送数据,进程2会立刻将接收到的该数据打印出来。如此循环往复。


总结

对于fgets有疑问的读者可以参考下面的文章:
Linux----标准IO文件操作函数总结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SigmaBull

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值