先看在项目中的实例
- 定义使用接口
(1)定义消息队列的大小
#define MAX_QUEUEMSGNUM (64) /*消息队列的消息数*/
#define MAX_QUEUEMSGSIZE (256) /*消息队列的消息大小*/
/*定义消息队列的结构体*/
typedef struct
{
int wordMsg1st;
int wordMsg2nd;
int wordMsg3rd;
int wordMsg4th;
}t_queueMsg;
typedef struct msgBufStr
{
int mtype; /*消息类型必须大于0*/
char mtext[MAX_QUEUEMSGSIZE];
}t_msgBuf;
(2)获取创建消息队列的keyID
/*获取创建消息队列的keyID,各进程约定以/home/文件夹下的szName文件来产生key*/
int osGetKeyID(char *szName)
{
key_t keyID;
keyID=ftok("/home/",atol(szName));
return keyID;
}
(3)创建消息队列szName:请取ASCII吗
bool osCreateQueue(char *szName,int queueNum,int queueSize,int dwFlag, unsigned int *queueID)
{
int keyID;
unsigned ine tempID;
struct msqid_ds msg_info;
keyID = osGetKeyID(szName);
if(0 > (tempID = msgget(keyID, 0666|IPC_CREAT)))
{
printf("msgget error\n");
return false;
}
/*获取消息队列的属性*/
if (!msgctl(tempID, IPC_STAT, &msg_info))
{
msgctl(tempID, IPC_RMID, NULL);/*删除队列*/
return false;
}
/*根据入参调整消息队列的属性*/
msg_info.msg_qbytes = queueNum * queueSize;/*消息队列的最大长度*/
if (!msgctl(tempID, IPC_SET, &msg_info))/*调整队列属性失败*/
{
msgctl(tempID, IPC_RMID, NULL);/*删除队列*/
return false;
}
*udwQueueID = tempID;
return true;
}
(4)发送消息
int osQueueSndMsg(unsigned queueID, T_MSGBUF *msg, int dwFlag)
{
int res;
int msgSize = MAX_QUEUEMSGSIZE;
res = msgsnd(queueID, msg, msgSize, dwFlag);
if(SUCCESS != res)
{
fprintf(stderr, "msgsnd failed \n");
return res;
}
//printf("msgsnd lenth:%d\n", sizeof(QUEUE_MESSAGE));
return res;
}
(5)接收消息
int osQueueRcvMsg(unsigned int queueID, int msgtype, T_MSGBUF *msg, int dwFlag)
{
int rcvLen;
int queueSize = MAX_QUEUEMSGSIZE;
rcvLen = msgrcv(queueID, msg, queueSize, msgtype, dwFlag);
if(rcvLen < 0)
{
return rcvLen;
}
if(rcvLen < queueSize)
{
//printf("rcvmsg rcvLen < dwQueueSize revlen:%d\n", rcvLen);
return false;
}
//printf("rcvmsg rcvLen:%d\n", rcvLen);
return rcvLen;
}
(6)删除消息队列
int osQueueDelete(unsigned int queueID)
{
return msgctl(queueID, IPC_RMID, NULL);
}
- 使用接口
(1)根据业务需要创建A进程的消息队列
#define QueueName 100011 // 根据业务定义
char queueName[32];
unsingned int queueID = 0;
memset(queueName, 0x0, sizeof(queueName));
sprintf(queueName,"%d", QueueName);
int ret = osCreateQueue(queueName, MAX_QUEUEMSGNUM, MAX_QUEUEMSGSIZE, 0, &queueID);
if(ret == false)
{
printf("create %s queueID fail \n", queueName);
return;
}
(2)向A进程发送消息
boot sndMsgToProcA(unsigned int queueID, int msgtype)
{
int res = 0;
t_msgBuf stMsg;
t_queueMsg message;
memset(&stMsg,0x0,sizeof(t_msgBuf));
memset(&message,0x0,sizeof(t_queueMsg));
message.wordMsg1st = msgtype;
stMSG.mtype = APP_MSG_TYPE; // 自定义消息类型
memcpy(stMSG.mtext, &message, sizeof(t_queueMsg));
res = osQueueSndMsg(queueID, &stMSG, IPC_NOWAIT);
if(!res)
{
printf("send data error\n");
return false;
}
return true;
}
=========================================================================
以下概念的叙述为转载:
linux基础——linux进程间通信(IPC)机制总结_千里之行,始于足下-优快云博客_linux 进程间通信
消息队列是内核地址空间中的内部链表,通过linux内核在各个进程直接传递内容,消息顺序
地发送到消息队列中,并以几种不同的方式从队列中获得,每个消息队列可以用 IPC标识符 唯一
地进行识别。内核中的消息队列是通过IPC的标识符来区别,不同的消息队列直接是相互独立的。
每个消息队列中的消息,又构成一个 独立的链表。
消息队列克服了信号承载信息量少,管道只能承载无格式字符流。
(1)消息缓冲区结构:
// 头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
// 在结构中有两个成员:
// mtype为消息类型,用户可以给某个消息设定类型,可以在消息队列中正确地发送和接受自己的消息
// mtext为消息数据,采用柔性数组,用户可以重新定义msgbuf结构。例如:
struct msgbuf{
long mtype;
char mtext[1];//柔性数组
}
用户不可随意定义msgbuf结构,因为在linux中消息的大小有限制,在linux/msg.h中定义如下:
#define MSGMAX 8192
消息总的大小不能超过8192个字节,包括mtype成员(4个字节)。
(2)msqid_ds内核数据结构。
struct msgid_ds{
struct ipc_perm msg_perm{
time_t msg_stime;
time_t msg_rtime;
time_t msg_ctime;
unsigned long _msg_cbuyes;
..........
}
};
Linux内核中,每个消息队列都维护一个结构体,此结构体保存着消息队列当前状态信息,该
结构体在头文件linux/msg.h中定义。
(3)ipc_perm内核数据结构
struct ipc_perm{
key_t key;
uid_t uid;
gid_t gid;
.......
};
结构体ipc_perm保存着消息队列的一些重要的信息,比如说消息队列关联的键值,消息队列
的用户id组id等。它定义在头文件linux/ipc.h中。
常用函数:
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该
id值通过ftok函数得到。
关于ftok函数,可以看这篇博文:
转载:ftok()函数深度解析_u013485792的专栏-优快云博客_ftok函数作用
消息队列的本质
Linux的消息队列(queue)实质上是一个链表,它有消息队列标识符(queue ID)。 msgget创建
一个新队列或打开一个存在的队列;msgsnd向队列末端添加一条新消息;msgrcv从队列中取消
息, 取消息是不一定遵循先进先出的, 也可以按消息的类型字段取消息。
消息队列与命名管道的比较
消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可
以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。在命名管道中,发送数据
用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们
对每个数据都有一个最大长度的限制。
与命名管道相比,消息队列的优势在于:
1、消息队列可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭
时可能产生的困难。
2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步
方法。
3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样只能默认地接收