进程通信之消息队列

03月28日 收藏 0 评论 0 测试开发

进程通信之消息队列

转载声明:文章来源https://zhuanlan.zhihu.com/p/68910112

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

消息队列的概念

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

乍一看消息队列类似于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 %d\n", 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 %d\n", 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 %s\n", 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也是一样的,从而实现进程间消息传递。

下图是运行结果:

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

总结

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

C 0条回复 评论

帖子还没人回复快来抢沙发