消息队列介绍
消息队列:IPC之一
内核开辟的一个队列,进程可以通过调用系统API方式调用消息队列函数,给内核消息队列发送或者接收数据
涉及函数:
包含头文件:<sys/msg.h><sys/types.h>和<sys/ipc.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgget(key_t key, int msgflg);
msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msg_typ, int msgflg);
msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
ipcs命令可以查看消息队列,也可以查看共享内存。进程结束消息队列还存在,说明消息队列是由内核维护的
下文中1:代表参数一的解释
msgget:创建和访问一个消息队列
msgget用来创建和访问一个消息队列
int msgget(key_t key, int msgflg);
1:key_t用户指定的要创建的消息队列的名字(一般为整形数字)
2:msgflg权限位:0644,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:
如果操作成功,msgget将返回一个非负整数,即该消息队列的标识码;如果失败,则返回“-1”
例子:
msg_id = msgget((key_t)1122, IPC_CREAT | 0666);
msgsnd:发送信息,把一条消息添加到消息队列里去
msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
1:由msgget函数返回的消息队列标识码
2:是指针,指针指向准备发送的消息的结构体
发送消息struct msgbuf的标准:
The msgp argument is a pointer to a caller-defined structure of the
following general form:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
3:msg_sz发送结构体中除long int 的大小,也就是struct msgbuf中的char mtext的大小
4:控制着当前消息队列满或到达系统上限时将要发生的事情
msgflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误。
返回值:返回“0”,如果失败,则返回“-1”
例子:
if(msgsnd(msg_id,&msginfo,sizeof(msginfo.message),0)==-1)
{
perror("message send error:");
}
msgrcv:从一个消息队列里检索(接收)消息
msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msg_typ, int msgflg);
1:msgid: 由msgget函数返回的消息队列标识码
2:msg_ptr:是一个指针,指针指向准备接收的消息,
3:msg_sz发送结构体中除long int 的大小,也就是struct msgbuf中的char mtext的大小
4:msgtype:它可以实现接收优先级的简单形式
一个消息队列可以被很多进程共享,也就是多个进程都可能使用这个消息队列,那么消息如何进行区分?——mtype
mtype用来区别不同消息通常是,发送和接收的mtype数字一一对应才可以收到,当mtype==0:接收所有消息
如果mtype的值在消息队列中没有对应值且不为0,则接收将堵塞
• msgtype=0返回队列第一条信息
• msgtype>0返回队列第一条类型等于msgtype的消息
• msgtype<0返回队列第一条类型小于等于msgtype绝对值的消息
5:msgflg:控制着队列中没有相应类型的消息可供接收时将要发生的事
• msgflg=IPC_NOWAIT,队列没有可读消息不等待,返回ENOMSG错误。
• msgflg=MSG_NOERROR,消息大小超过msgsz时被截断
• msgtype>0且msgflg=MSC_EXCEPT,接收类型不等于msgtype的第一条消息。
返回值:成功返回实际放到接收缓冲区里去的字符个数returns the number of bytes actually copied into the
mtext array.如果失败,则返回“-1”
例子:
if (msgrcv(msg_id, &msginfo, sizeof(msginfo.message), 5, IPC_NOWAIT) == -1)//msgrcv接收,mtype和发送的mtype不一样也可以收到
{
perror("message recv error:");
return -1;
}
注意:
1.当重复往消息队列里面发送相同时间的时候,消息是不会被阻塞的,每一次发送都有效且相互独立
2.如果消息队列里面没有数据了,再接收也将阻塞,若不想阻塞,可设置msgflg=IPC_NOWAIT,将立刻返回并产生错误
IPC_NOWAIT
Return immediately if no message of the requested type is in the queue. The system call fails with errno set to ENOMSG.
3.最多可以创建256个消息队列
4.发送的每个消息的最大长度是8192字节
5.一个消息队列接收所有消息的最大容量是16384字节,16384/8192==2
代码实例
消息队列发送端:
#include <iostream>
#include<unistd.h>//unix stand lib
#include<sys/types.h>
#include<sys/fcntl.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<dirent.h>//file dir
#include <sys/wait.h>//wait func
#include <stdlib.h>//ststem
#include <signal.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
typedef struct
{
long mtype;
char message[50];
}MSG_DATA;
//====================================queue
int main(int argc, char *argv[])
{
int msg_id;
msg_id = msgget((key_t)1122, IPC_CREAT | 0666);
if (msg_id == -1)
{
perror("msgget error:");
}
MSG_DATA msginfo;
msginfo.mtype = 5;//指定mtype
strcpy(msginfo.message, "hello message!");
if(msgsnd(msg_id,&msginfo,sizeof(msginfo.message),0)==-1)
{
perror("message send error:");
}
cout << "message send success" << endl;
return 0;
}
消息队列接收端:
#include <iostream>
#include<unistd.h>//unix stand lib
#include<sys/types.h>
#include<sys/fcntl.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<dirent.h>//file dir
#include <sys/wait.h>//wait func
#include <stdlib.h>//ststem
#include <signal.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
typedef struct
{
long mtype;
char message[50];
}MSG_DATA;
//========================================queue===============
int main(int argc, char *argv[])
{
int msg_id;
msg_id = msgget((key_t)1122, IPC_CREAT | 0666);
if (msg_id == -1)
{
perror("msgget error:");
return -1;
}
MSG_DATA msginfo;
bzero(&msginfo,sizeof(msginfo));//清空用于接收
if (msgrcv(msg_id, &msginfo, sizeof(msginfo.message), 5, IPC_NOWAIT) == -1)//msgrcv接收,mtype和发送的mtype不一样也可以收到
{
perror("message recv error:");
return -1;
}
cout << "message recv " << msginfo.message<< endl;
return 0;
}