基本函数说明
- int msgget (key_t __key, int __msgflg),创建消息队列;或者返回已经存在的消息队列的ID;
- int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf),消息队列控制,如删除消息队列,获取消息队列的信息等;
- ssize_t msgrcv (int __msqid, void *__msgp, size_t __msgsz, long int __msgtyp, int __msgflg),从消息队列收取消息;
- int msgsnd (int __msqid, const void *__msgp, size_t __msgsz,int __msgflg)将消息发送到消息队列中;
- key_t ftok (const char *__pathname, int __proj_id)通过一个路径名和project ID产生一个key;
消息队列示例
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
typedef unsigned char BOOL;
#define MSG_LEN 1024
#define PROJECT_ID 0x007
#define TRUE 1
#define FALSE 0
#define DBG_STATE() //{printf("zoobi %s %d\n", __FUNCTION__, __LINE__);}
/**
* 定义消息结构体,第一个成员必须是int型(测试用环境是64bit fedora27);
*/
typedef struct msgBody
{
int msgType;
char msgData[MSG_LEN];
}MSGBody;
/**
* 创建消息队列或者获取已经存在的消息队列ID;
* @Param 传入一个可打开的文件路径(可以是目录或者文件),直接传入NULL则创建的消息队列在本进程使用
* (如果将ID以另外的方式给到其他进程,其他进程也可用使用这个消息队列)
* @return 返回获取到的消息队列ID
*/
int queueCreate(const char* path)
{
key_t queueKey;
if(path)
{
/**
* ftok()从一个路径上项目ID上产生一把key;
*/
queueKey = ftok(path, PROJECT_ID);
/**
* 直接通过key去获取已经存在的消息队列ID;如果不存在,则创建消息队列;
* PC_CREAT|IPC_EXCL这两个flag一起或时,如果已经存在相同key的消息队列,则获取消息队列失败,返回-1
* 并且这样创建的消息队列,如果没有显式的使用msgctl去删除消息队列,在进程退出后消息队列依然存在;
*/
return msgget(queueKey, 0666|IPC_CREAT);
}
else
{
DBG_STATE();
/**
* 传入key为IPC_PRIVATE,直接创建消息队列;flag为IPC_CREAT,表示如果没有该key的消息队列就创建;
* IPC_CREAT|IPC_EXCL这两个flag一起或时,如果已经存在相同key的消息队列,则获取消息队列失败,返回-1;
* 正常情况下msgget应该返回消息队列ID;
*/
return msgget(IPC_PRIVATE, 0666|IPC_CREAT);
}
}
int messageSend(int msgID, const void* buffer, unsigned bufLen, BOOL bWait)
{
MSGBody msgData;
memset((void*)&msgData, 0x00, sizeof(MSGBody));
/**
* 将要发送的消息拷贝到消息结构体中,并设定消息类型;
*/
msgData.msgType = 0;
memcpy((void*)(msgData.msgData), buffer, bufLen);
printf("the send data is:%s", msgData.msgData);
DBG_STATE();
if(bWait)
{
/**
* __msgflg设定为0,表示当消息队列满时,阻塞发送消息;
*/
return msgsnd(msgID, (const void*)&msgData, sizeof(msgData.msgData), 0);
}
else
{
/**
* __msgflg设定为IPC_NOWAIT,表示当消息队列满时,不阻塞发送消息,立即返回错误,错误号写入errno;
*/
return msgsnd(msgID, (const void*)&msgData, sizeof(msgData.msgData), IPC_NOWAIT);
}
}
int messageRecive(int msgID, void* buffer, unsigned bufLen, BOOL bWait)
{
MSGBody msgData;
int ret = 0;
if(bWait)
{
DBG_STATE();
/**
* 从消息队列中获取消息,会一直等到有可用消息后才返回;
* __msgtyp设定为0,表示不关注消息的type,如果为其他值,则一定是要符合要求消息才会接收到;
*/
ret = msgrcv(msgID, (void*)&msgData, sizeof(msgData.msgData), 0, 0);
DBG_STATE();
memcpy(buffer, (const void*)(msgData.msgData), MSG_LEN);
return ret;
}
else
{
DBG_STATE();
/**
* 从消息队列中获取消息,不阻塞,无消息可获取的话返回-1,错误号写入errno;
* __msgtyp设定为0,表示不关注消息的type,如果为其他值,则一定是要符合要求消息才会接收到;
*/
ret = msgrcv(msgID, (void*)&msgData, sizeof(msgData.msgData), 0, IPC_NOWAIT);
if(ret == -1)
{
printf("msgrcv failed! errno:%s\n", strerror(errno));
return ret;
}
else
{
DBG_STATE();
memcpy(buffer, (const void*)msgData.msgData, MSG_LEN);
return ret;
}
}
}
void queueDestroy(int msgID)
{
/**
* 删除消息队列;
*/
msgctl(msgID, IPC_RMID, NULL);
}
static void* _testThread1(void* arg)
{
int msgID = *((int*)arg);
char buffer[MSG_LEN];
while(1)
{
DBG_STATE();
if(messageRecive(msgID, buffer, MSG_LEN, TRUE)>0)
{
printf("The recive str is:%s\n", buffer);
}
else
{
printf("messageRecive failed!\n");
}
sleep(1);
}
}
int main(int argc, char* argv[])
{
static int msg1ID = 0;
pthread_t thread1ID;
char getStrBuf[MSG_LEN+1];
struct msqid_ds msgInfo;
msg1ID = queueCreate(NULL);
if(msg1ID < 0)
{
printf("msgget failed, errno:%s\n", strerror(errno));
return -1;
}
DBG_STATE();
/**
* 创建消息队列接收线程;
*/
if(0 != pthread_create(&thread1ID, NULL, _testThread1, (void*)&msg1ID))
{
printf("pthread_create failed!\n");
return -1;
}
DBG_STATE();
while(1)
{
DBG_STATE();
fgets(getStrBuf, MSG_LEN, stdin);
if(0 == strncmp(getStrBuf, "exit", 4))
{
queueDestroy(msg1ID);
exit(0);
}
else if(0 == strncmp(getStrBuf, "EXIT", 4))
{
queueDestroy(msg1ID);
exit(0);
}
else if(0 == strncmp(getStrBuf, "msginfo", 7))
{
/**
* 获取消息队列的状态信息,获取的结构体为struct msqid_ds;
* 其中msg_qbytes表示消息队列的空间大小;msg_qnum表示消息队列中的消息个数;
* msg_cbytes表示消息队列已经使用的空间大小;
* 在fedora27测试环境下,msg_cbytes为16KB,如果一个消息占用1KB,则消息队列中最多
* 保留16个消息;
* 消息队列的最大空间大小和消息的最大大小写死在kernel中,如果需要更改该大小,需要更改
* msg.h中的如下值并重新编译kernel替换之:
* #define MSGMNI 32000 max # of msg queue identifiers
* #define MSGMAX 8192 max size of message (bytes)
* #define MSGMNB 16384 default max size of a message queue
*/
if(msgctl(msg1ID, IPC_STAT, &msgInfo)==0)
{
printf("current number of bytes on queue:0x%x\n", msgInfo.msg_cbytes);
printf("number of messages in queue:0x%x\n", msgInfo.msg_qnum);
printf("max number of bytes on queue:0x%x\n", msgInfo.msg_qbytes);
}
continue;
}
if(messageSend(msg1ID, getStrBuf, MSG_LEN, TRUE)!=0)
{
printf("messageSend failed,errno:%s\n", strerror(errno));
}
}
return 0;
}
然后编译运行:
[zoobi@localhost linux_env]$ gcc msg_queue.cpp -o msgTest -lpthread -lstdc++
[zoobi@localhost linux_env]$ ./msgTest
hello
the send data is:hello
The recive str is:hello
zoobi
the send data is:zoobi
The recive str is:zoobi
my name is zoobi
the send data is:my name is zoobi
The recive str is:my name is zoobi
heihei
the send data is:heihei
The recive str is:heihei
msginfo
current number of bytes on queue:0x0
number of messages in queue:0x0
max number of bytes on queue:0x4000
exit
[zoobi@localhost linux_env]$