1.消息队列的使用方法
1.1发送者:
A) 获取消息队列的 ID
B) 将数据放入一个附带有标识的特殊的结构体,发送给消息队列。
1.2接收者:
A) 获取消息队列的 ID
B) 将指定标识的消息读出。
当发送者和接收者都不再使用消息队列时,及时删除它以释放系统资源。
2.API函数
2.1获取消息队列的 ID
注意:
2.1.1,选项 msgflg 是一个位屏蔽字,因此 IPC_CREAT、IPC_EXCL 和权限 mode 可以用位
或的方式叠加起来,比如:msgget(key, IPC_CREAT | 0666); 表示如果 key 对应的消息队
列不存在就创建,且权限指定为 0666,若已存在则直接获取 ID。
2.1.2,权限只有读和写,执行权限是无效的,例如 0777 跟 0666 是等价的。
2.1.3,当 key 被指定为 IPC_PRIVATE 时,系统会自动产生一个未用的 key 来对应一个新的
消息队列对象。一般用于线程间通信。
2.2发送与接收信息
注意:
2.2.1,发送消息时,消息必须被组织成以下形式:
struct msgbuf
{
long mtype; // 消息的标识
char mtext[1]; // 消息的正文
};
也就是说:发送出去的消息必须以一个 long 型数据打头,作为该消息的标识,后
面的数据则没有要求。
2.2.2,消息的标识可以是任意长整型数值,但不能是 0L。
2.2.3,参数 msgsz 是消息中正文的大小,不包含消息的标识。
2.3设置或者获取消息队列的相关属性
注意:
2.3.1,IPC_STAT 获得的属性信息被存放在以下结构体中:
struct msqid_ds
{
struct ipc_perm msg_perm; /* 权限相关信息 */
time_t msg_stime; /* 最后一次发送消息的时间 */
time_t msg_rtime; /* 最后一次接收消息的时间 */
time_t msg_ctime; /* 最后一次状态变更的时间 */
unsigned long __msg_cbytes; /* 当前消息队列中的数据尺寸 */
msgqnum_t msg_qnum; /* 当前消息队列中的消息个数 */
msglen_t msg_qbytes; /* 消息队列的最大数据尺寸 */
pid_t msg_lspid; /* 最后一个发送消息的进程 PID */
pid_t msg_lrpid; /* 最后一个接收消息的进程 PID */
};
其中,权限相关的信息用如下结构体来表示:
struct ipc_perm
{
key_t __key; /* 当前消息队列的键值 key */
uid_t uid; /* 当前消息队列所有者的有效 UID */
gid_t gid; /* 当前消息队列所有者的有效 GID */
uid_t cuid; /* 当前消息队列创建者的有效 UID */
gid_t cgid; /* 当前消息队列创建者的有效 GID */
unsigned short mode; /* 消息队列的读写权限 */
unsigned short __seq; /* 序列号 */
};
2.3.2,当使用 IPC_INFO 时,需要定义一个如下结构体来获取系统关于消息队列的限制值
信息,并且将这个结构体指针强制类型转化为第三个参数的类型。
struct msginfo
{
int msgpool; /* 系统消息总尺寸(千字节为单位)最大值 */
int msgmap; /* 系统消息个数最大值 */
int msgmax; /* 系统单个消息尺寸最大值 */
int msgmnb; /* 写入消息队列字节数最大值 */
int msgmni; /* 系统消息队列个数最大值 */
int msgssz; /* 消息段尺寸 */
int msgtql; /* 系统中所有消息队列中的消息总数最大值 */
unsigned short int msgseg; /* 分配给消息队列的数据段的最大值 */
};
2.3.3,当使用选项 MSG_INFO 时,跟 IPC_INFO 一样也是获得一个 msginfo 结构体的信息,
但是有如下几点不同:
成员 msgpool 记录的是系统当前存在的 MSG 的个数总和
成员 msgmap 记录的是系统当前所有 MSG 中的消息个数总和
成员 msgtql 记录的是系统当前所有 MSG 中的所有消息的所有字节数总和
3.例子
两个进程之间通信,一个发送信息,一个接收信息
发送信息进程程序
#include "unistd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#include "signal.h"
#include <wiringPi.h>
#define MSG1 1 //指定标识
#define MSG2 2 //指定标识
#define TEXTSIZE 128 //数据内存大小
struct mybuf
{
long mytype;
char msgtext[TEXTSIZE];
};
int msgid;
void routine1(int signum)
{
printf("MSG1 exit handler.\n");
msgctl(msgid, IPC_RMID, NULL);
exit(0);
}
int main(int argc, char *argv[])
{
int i = 0;
int ret = -1;
struct mybuf msg;
msgid = msgget(ftok(".", 1), IPC_CREAT | 0666); //获取消息队列的ID
if(msgid < 0) return -1;
signal(SIGINT, routine1);
while(1)
{
msg.mytype = MSG1;
sprintf(msg.msgtext, "send msg1\n");
ret = msgsnd(msgid, &msg, strlen(msg.msgtext), 0); //直到发送完或者发送错误才返回
if(ret == -1)return -2; //发送失败
msg.mytype = MSG2;
sprintf(msg.msgtext, "send msg222\n");
ret = msgsnd(msgid, &msg, strlen(msg.msgtext), 0);
if(ret == -1)return -2;
printf("msg file send%d over\n", i++);
delay(1000); //ms
}
exit(0); //0表示正常退出,同时冲洗缓冲区数据,并执行退出处理函数
}
接收进程程序
#include "unistd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#include "signal.h"
#include <wiringPi.h>
#define MSG1 1 //指定标识
#define MSG2 2 //指定标识
#define TEXTSIZE 128 //数据内存大小
struct mybuf
{
long mytype;
char msgtext[TEXTSIZE];
};
int msgid;
void routine1(int signum)
{
printf("MSG222 exit handler.\n");
msgctl(msgid, IPC_RMID, NULL);
exit(0);
}
int main(int argc, char *argv[])
{
int i = 0;
int ret = -1;
struct mybuf msg;
msgid = msgget(ftok(".", 1), IPC_CREAT | 0666); //获取消息队列的ID
if(msgid < 0) return -1;
signal(SIGINT, routine1);
while(1)
{
ret = msgrcv(msgid, &msg, TEXTSIZE, MSG1, 0); //等待接受完才返或错误返回
if(ret == -1) //接受失败
{
printf("recive is failure\n");
return -2;
}
printf(" rcv:%s", msg.msgtext);
ret = msgrcv(msgid, &msg, TEXTSIZE, MSG2, 0);
if(ret == -1) //接受失败
{
printf("recive is failure\n");
return -2;
}
printf(" rcv:%s", msg.msgtext);
delay(500); //ms
}
exit(0); //0表示正常退出,同时冲洗缓冲区数据,并执行退出处理函数
}