linux消息队列操作

基本函数说明

  • 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]$ 

猜你喜欢

转载自blog.csdn.net/zyj_zhouyongjun183/article/details/80156647