Linux应用程序开(day15) ── 消息队列

内容

介绍

消息队列也能实现不同进程之间的通信。和管道不同的是每条消息都有类型有格式的,他可以实现消息的随机查询,可以不按照先入先出的原则,只有内核重启或者人工删除的时候消息队列才回被删除,否则一直存在于内存之中,所以我们指定IPC键值的时候要保证唯一。消息队列的个数最多16个,总容量最多为16384个字节,每个消息的内容最多8192字节。和原道一样,数据读取了以后就会被删除。

获取键值

可以通过ftok()来获取到一个唯一的IPC键值

key_t ftok(const char *pathname, int proj_id)

依赖的头文件:

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

参数:
pathname:路径名
proj_id:项目id
返回值:成功返回key,失败返回-1

创建消息队列

可以通过msgget()来获取到一个唯一的IPC键值

int msgget(key_t key, int msgflg)

依赖的头文件:

#include <sys/msg.h>

参数:
key:ICP键值,一般要保证唯一性
msgflg:函数的行为IPC_CREAT(创建)或IPC_EXCL(如果已经存在则返回失败)
返回值:成功返回队列标识符,失败返回-1

消息的格式

首先要指定消息的类型,必须为长整型,并且是结构体的第一个成员。说明:此时的类型是指的这个消息的类型,这一个消息队列可以传输好多消息,可以按照消息的类型进行区分,相当于消息的id。

typedef struct _msg
{
long mtype;
/*消息类型*/
char mtext[100];
/*消息正文*/
... /*消息的正文可以有多个成员*/
}MSG;

发送消息

可以通过msgsnd()来发送消息

int msgsnd(int msqid, const void *msgp,size_t msgsz, int msgflg);

依赖的头文件:#include <sys/msg.h>

#include <sys/msg.h>

参数:
msqid:消息队列的id
msgp:要发送的消息的结构体
msgsz:消息正文的长度
msgflg:控制条件,0:msgsnd调用阻塞直到条件满足为止。IPC_NOWAIT: 若消息没有立即发送则调用该函数的进程会立即返回。

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

接收消息

可以通过msgrcv()来接收消息

ssize_t msgrcv(int msqid, void *msgp, size_tmsgsz, long msgtyp, int msgflg);

依赖的头文件:#include <sys/msg.h>

#include <sys/msg.h>

参数:
msqid:消息队列的id
msgp:存放消息的结构体,要与发送方的一致。
msgsz:消息正文的长度
msgtyp:msgtyp = 0:返回队列中的第一个消息;msgtyp > 0:返回队列中消息类型为msgtyp的消息;msgtyp < 0:返回队列中消息类型值小于或等于msgtyp绝对值的消息,如果这种消息有若干个,则取类型值最小的消息
msgflg:控制条件,0:msgrcv调用阻塞直到接收消息成功为止。MSG_NOERROR:若返回的消息字节数比nbytes字节数
多,则消息就会截短到nbytes字节,且不通知消息发送进程。IPC_NOWAIT:调用进程会立即返回。若没有收到消息则立即返回-1
返回值:成功返回实际读取到的消息的长度,失败返回-1

测试

正常发送和接收

我们在写端调用msgsnd()函数将消息传送过去,从读端用msgrcv()将数据读出来,这里需要注意的是:写端的key、消息类型要和读端的一致,具体的代码如下:
写端:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
typedef struct _msg{
	long mtype;
	char mtext[50];
}MSG;
void main(){
	key_t key;
	int msgqid;
	MSG msg;
	key = ftok(".",666);
	printf("key:%d\n",key);
	
	msgqid = msgget(key,IPC_CREAT|0666);

	if(msgqid == -1)
	{
		perror("msdget出错\n");
		exit(-1);
	}

	msg.mtype = 10;
	strcpy(msg.mtext,"helloworld");
	msgsnd(msgqid,&msg,sizeof(msg.mtext),0);
}

读端:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
typedef struct _msg{
	long mtype;
	char mtext[50];
}MSG;
void main(){
	
	key_t key;
	int msgqid;
	MSG msg;

	key = ftok(".",666);
	msgqid = msgget(key,IPC_CREAT|0666);
	if(msgqid == -1)
	{
		perror("msgget错误\n");
		exit(-1);
	}
	msgrcv(msgqid,&msg,sizeof(msg.mtext),10,0);
	printf("获取到的数据为:【%s】\n",msg.mtext);


}

运行结果:

在这里插入图片描述

修改接收端的key,使之与发送端的key不一致

修改后,两端的key值不同,生成的消息队列自然也不会相同,所以二者之间不能进行通信。读端会进入阻塞状态。
运行结果:
在这里插入图片描述

收发两条消息类型不同的消息

我们分别发送两条消息类型为10和11的两条消息,然后再从读端将两条消息读取出来。
写端代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
typedef struct _msg{
	long mtype;
	char mtext[50];
}MSG;
void main(){
	key_t key;
	int msgqid;
	MSG msg;
	key = ftok(".",666);
	printf("key:%d\n",key);
	
	msgqid = msgget(key,IPC_CREAT|0666);
	printf("msgqid:%d \n",msgqid);
	if(msgqid == -1)
	{
		perror("msdget出错\n");
		exit(-1);
	}

	msg.mtype = 10;
	strcpy(msg.mtext,"helloworld");
	msgsnd(msgqid,&msg,sizeof(msg.mtext),0);
	printf("10号消息发送成功\n");


	msg.mtype = 11;
	strcpy(msg.mtext,"hi everyone");
	msgsnd(msgqid,&msg,sizeof(msg.mtext),0);
	printf("11号消息发送成功\n");
}

读端代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
typedef struct _msg{
	long mtype;
	char mtext[50];
}MSG;
void main(){
	
	key_t key;
	int msgqid;
	MSG msg;

	key = ftok(".",666);
	printf("key:%d \n",key);
	msgqid = msgget(key,IPC_CREAT|0666);
	printf("msgqid:%d \n",msgqid);
	if(msgqid == -1)
	{
		perror("msgget错误\n");
		exit(-1);
	}
	msgrcv(msgqid,&msg,sizeof(msg.mtext),10,0);
	printf("10号获取到的数据为:【%s】\n",msg.mtext);
	
	msgrcv(msgqid,&msg,sizeof(msg.mtext),11,0);
	printf("11号获取到的数据为:【%s】\n",msg.mtext);


}

运行结果表名两条消息都可以正常收到,结果如下图所示:
在这里插入图片描述

作业

通过消息队列,实现进程间收发字符串"hello world" 的功能。
答案:上述【正常发送和接收】部分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值