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