版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/88092758
消息队列用于运行于同一台机器上的进程间通信,它和管道和相似,是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现。消息链表中节点的结构用 声明。
消息队列
(1)创建新消息队列或取得已存在消息队列,函数原型:
int msgget(key_t key, int msgflg);
- 1)参数 可以认为是一个端口号,也可以由函数 生成
- 2) 如果等于 _ ,若没有该队列,则创建一个并返回新标识符,若已存在则返回原标识符; 如果等于 _ ,若没有该队列,则返回-1,若已存在,则返回0
(2)向队列读/写消息,函数原型如下所述:
从队列中取用消息:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
将数据放到消息队列中:
int msgsnd(int msqid, cosnt void *msgp, size_t msgsz, int msgflg);
- 1) 是消息队列的标识码
- 2) 是指向消息缓冲区的指针,此位置用来暂时存储发送和接收的信息,是一个用户可定义的通用结构,但一般定义为:
struct msgstru {
long mtype;
char mtext[512];
}
- 3) 是指消息的大小
- 4) 是指从消息队列内读取的消息形态。如果值为0,则标识消息队列中的所有消息都会被读取
- 5) :用来指明核心程序没有数据的情况下所应采取的行动。如果 和常数 _ 合用,则在 执行时若是消息队列已满,则 将不会阻塞,而会立即返回-1,如果执行的是 ,则在消息队列呈空时,不做等待马上返回-1,并设定错误码为 .当 为0时, 及 在队列呈满或呈空的情形时,采取阻塞等待的处理模式
(3)设置消息队列属性,函数原型:
int msgctl(int msgqid, int cmd, struct msqid_ds *buf);
- 参数中的 系统调用对 标识的消息队列执行 操作,系统定义了3种 操作: _ 、 _ 、 _ RMID 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)在命名管道中,发送数据用 函数,接受数据用 函数,而在消息队列中,发送数据用 函数,接收数据用 函数,而且它们对每个数据都有一个最大长度的限制
不同点:
- 1)消息队列也可以独立发送和接受进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难
- 2)可以同时通过发送消息以避免命名管道的同步和阻塞问题,而不需要进程来提供同步方法
- 3)接受程序可以通过消息类型有选择地接受数据,而不是像命名管道中那样,只能默认地接受