进程间通信(二)消息队列

版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/88092758

消息队列用于运行于同一台机器上的进程间通信,它和管道和相似,是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现。消息链表中节点的结构用 m s g msg 声明。

消息队列

(1)创建新消息队列或取得已存在消息队列,函数原型:

int msgget(key_t key, int msgflg);
  • 1)参数 k e y key 可以认为是一个端口号,也可以由函数 f t o k ftok 生成
  • 2) m s g f l g msgflg 如果等于 I P C IPC _ C R E A T CREAT ,若没有该队列,则创建一个并返回新标识符,若已存在则返回原标识符; m s g f l g msgflg 如果等于 I P C IPC _ E X C L EXCL ,若没有该队列,则返回-1,若已存在,则返回0

(2)向队列读/写消息,函数原型如下所述:

m s g r c v msgrcv 从队列中取用消息:

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

m s g s n d msgsnd 将数据放到消息队列中:

int msgsnd(int msqid, cosnt void *msgp, size_t msgsz, int msgflg);
  • 1) m s q i d msqid 是消息队列的标识码
  • 2) m s g p msgp 是指向消息缓冲区的指针,此位置用来暂时存储发送和接收的信息,是一个用户可定义的通用结构,但一般定义为:
struct msgstru {
	long mtype;
	char mtext[512];
}
  • 3) m s g s z msgsz 是指消息的大小
  • 4) m s g t y p msgtyp 是指从消息队列内读取的消息形态。如果值为0,则标识消息队列中的所有消息都会被读取
  • 5) m s g f l g msgflg :用来指明核心程序没有数据的情况下所应采取的行动。如果 m s g f l g msgflg 和常数 I P C IPC _ N O W A I T NOWAIT 合用,则在 m s g s n d msgsnd 执行时若是消息队列已满,则 m s g s n d ( ) msgsnd() 将不会阻塞,而会立即返回-1,如果执行的是 m s g r c v msgrcv ,则在消息队列呈空时,不做等待马上返回-1,并设定错误码为 E N O M S G ENOMSG .当 m s g f l g msgflg 为0时, m s g s n d ( ) msgsnd() m s g r c v msgrcv 在队列呈满或呈空的情形时,采取阻塞等待的处理模式

(3)设置消息队列属性,函数原型:

int msgctl(int msgqid, int cmd, struct msqid_ds *buf);
  • 参数中的 m s g c t l msgctl 系统调用对 m s g q i d msgqid 标识的消息队列执行 c m d cmd 操作,系统定义了3种 c m d cmd 操作: I P C IPC _ S T A T STAT I P C IPC _ S E T SET I P C IPC _ RMID IPC$_ S T A T STAT 用来获取消息队列中对应的 m s q i d msqid _ d s ds 数据结构,并将其保存到 b u f buf 指定的地址空间; I P C IPC _ S E T SET 用来设置消息队列的属性,要设置的属性存储在 b u f buf 中; I P C IPC _ RMID 用来从内核中删除 msqid$的消息队列

例1:用消息队列来传输数据

//msgreceive.cpp
/*************************************************************************
      > File Name: msgreceive.cpp
      > Author: ersheng
      > Mail: [email protected] 
      > Created Time: Fri 01 Mar 2019 08:49:56 PM CST
 ************************************************************************/

#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
using namespace std;
#define BUFSIZE 512
struct msg_st {
	long int msg_type;
	char text[BUFSIZE];
};
int main() {
	int running = 1;
	int msgid = -1;
	struct msg_st data;
	long int msgtype = 0;
	//建立消息队列 
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
	if (msgid == -1) {
		fprintf(stderr, "msgget failed with errno: %d\n", errno);
		exit(EXIT_FAILURE);
	}
	//从队列中获取消息,直到遇到end消息为止 
	while (running) {
		if (msgrcv(msgid, (void *)&data, BUFSIZE, msgtype, 0) == -1) {
			fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
			exit(EXIT_FAILURE);
		}	
		printf("You wrote: %s\n", data.text);
		//遇到end结束 
		if (strncmp(data.text, "text", 3) == 0) {
			running = 0;
		}
	}
	//删除消息队列 
	if (msgctl(msgid, IPC_RMID, 0) == -1) {
		fprintf(stderr, "msgctl(IPC_RMID) failed\n");
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
}
//msgsend.cpp
/*************************************************************************
      > File Name: msgsend.cpp
      > Author: ersheng
      > Mail: [email protected] 
      > Created Time: Fri 01 Mar 2019 09:01:07 PM CST
 ************************************************************************/

#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>
using namespace std;
#define MAX_TEXT 512
#define BUFSIZE 512
struct msg_st {
	long int msg_type;
	char text[MAX_TEXT];
};
int main() {
	int running = 1;
	struct msg_st data;
	char buffer[BUFSIZE];
	int msgid = -1;
	//建立消息队列 
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
	if (msgid == -1) {
		fprintf(stderr, "msgget failed with error: %d\n", errno);
		exit(EXIT_FAILURE);
	}
	//向消息队列中写消息,直到写入end 
	while (running) {
		//输入数据 
		printf("Enter some text: ");
		fgets(buffer, BUFSIZE, stdin);
		data.msg_type = 1;
		strcpy(data.text, buffer);
		//向队列发送数据 
		if (msgsnd(msgid, (void *)&data, MAX_TEXT, 0) == -1) {
			fprintf(stderr, "msgsend failed\n");
			exit(EXIT_FAILURE);
		}
		//输入end结束输入 
		if (strncmp(buffer, "end", 3) == 0) {
			running = 0;
		}
		sleep(1);
	}
	exit(EXIT_SUCCESS);
}

在这里插入图片描述
在这里插入图片描述

消息队列与有名管道

相同点:

  • 1)消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送和接受的方式来传递数据的。
  • 2)在命名管道中,发送数据用 w r i t e write 函数,接受数据用 r e a d read 函数,而在消息队列中,发送数据用 m s g s n d msgsnd 函数,接收数据用 m s g r c v msgrcv 函数,而且它们对每个数据都有一个最大长度的限制

不同点:

  • 1)消息队列也可以独立发送和接受进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难
  • 2)可以同时通过发送消息以避免命名管道的同步和阻塞问题,而不需要进程来提供同步方法
  • 3)接受程序可以通过消息类型有选择地接受数据,而不是像命名管道中那样,只能默认地接受

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/88092758
今日推荐