消息队列
消息队列提供了向另一个进程发送一个数据块的方法,每个数据块均具有类型
消息队列是消息的链表,存放在内存中,由内核维护,其维护空消息队列,当进程需要传递消息时其申请空消息缓冲块填入数据,之后将消息块挂在另一个进程的消息队列上,当对方接收后会将此消息块从对方消息队列删除重新添加到空消息链表中。
消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队
列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有⼀个上限(MSGMNI)
消息队列函数:
消息队列创建
函数原型
int msgget(key_t key, int msgflg);
功能:用来创建和访问一个消息队列
参数:
key: 某个消息队列的名字 可以通过自己设定,也可以通过frok函数获得
key_t ftok(const char *pathname, int proj_id);
pathname路径名,proj_id项目名称一个非0整数(低8位有效)
msgflg: 用法和创建⽂文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1
消息队列控制
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:消息队列的控制函数
参数
msqid: 由msgget函数返回的消息队列标识码
cmd:是将要采取的动作,(有三个可取值)
返回值:成功返回0,失败返回-1
buf:msqid_ds 数据类型的地址,用来存放或更改消息队列的属性
cmd取值 | 说明 |
---|---|
IPC_START | 将 msqid_ds 相关的数据结构中各个元素的当前值存入到由 buf 指向的结构中 |
IPC_SET | 将 msqid_ds 相关的数据结构中的元素设置为由 buf 指向的结构中的对应值 |
IPC_RMID | 删除消息队列 |
消息格式
消息队列发送和接收均以消息类型为准,即所有发送的消息均为以下结构
消息结构参考形式如下:
struct msgbuf {
long mtype; //消息结构第一个必须为long int 类型,表示消息的类型
char mtext[1];
}
消息结构在两方⾯面受到制约:
首先,它必须小于系统规定的上限值;
其次,它必须以一个long int长整数开始,接收者函数将利用这个长整数确定消息的类型
向消息队列添加消息
函数原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:把一条消息添加到消息队列中
参数
msgid: 由msgget函数返回的消息队列标识码
msgp:是一个指针,指针指向准备发送的消息,
msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情
msgflg取值 IPC_NOWAIT 表示队列满不等待,返回EAGAIN错误,0 调用阻塞直到条件满足为止。
返回值:成功返回0;失败返回-1
从一个消息队列接受消息
函数原形:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数
msgid: 由msgget函数返回的消息队列标识码
msgp:是一个指针,指针指向准备接收的消息,
msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
msgflg:控制着队列中没有相应类型的消息可供接收时将要发生的事
返回值:成功返回实际放到接收缓冲区⾥里去的字符个数,失败返回-1
msgtype取值:
msgtype = 0 取消息队列中第一条消息
msgtype > 0 取消息队列中类型为msgtype 的消息
msgtype < 0 取消息队列中小于等于msgtype绝对值消息中类型最小的消息
在获取某类型消息的时候,若队列中有多条此类型的消息,则获取最先添加的消息
msgflg取值:
msgflg = IPC_NOWAIT 当消息队列中没有满足的消息时直接返回 errno 为ENOMSG
msgflg = MSG_NOERROR时 获取的消息长度大于msgsz时截断消息
msgflg = 0 阻塞直到获取到符合条件的消息
当msgtype = 0 msgflg = MSG_EXCEPT时返回第一条不等于msgtype类型的消息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define ERR_EXIT(m)\
do \
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
struct msgbuf{
long msgtype;
char mtext[1024];
};
int main()
{
key_t key = ftok(".", 0x66);
if(key < 0)
ERR_EXIT("ftok error");
int msqid = msgget(key, IPC_CREAT|IPC_EXCL|0666);
if(msqid < 0)
ERR_EXIT("msgget error");
struct msgbuf msg;
msg.msgtype = 10;
strcpy(msg.mtext, "hello");
if(msgsnd(msqid, (void *)&msg, sizeof(struct msgbuf) - sizeof(long), 0) < 0)
ERR_EXIT("msgsnd error");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define ERR_EXIT(m)\
do \
{ \
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
struct msgbuf{
long msgtype;
char mtext[1024];
};
int main()
{
key_t key = ftok(".", 0x66);
if(key < 0)
ERR_EXIT("ftok error");
int msqid = msgget(key, IPC_CREAT);
if(msqid < 0)
ERR_EXIT("msgget error");
struct msgbuf msg;
if(msgrcv(msqid, (void*)&msg, sizeof(struct msgbuf) - sizeof(long), 10, 0) < 0)
ERR_EXIT("msgsnd error");
printf("msg:%s\n", msg.mtext);
if(msgctl(msqid, IPC_RMID, NULL) < 0)
ERR_EXIT("msgctl error");
return 0;
}
ipcs & ipcrm命令
ipcs: 显⽰示IPC资源 ipcs -p 显示消息队列
ipcrm: ⼿手动删除IPC资源