目录

4.2 消息队列

4.2.1 概念和原理

4.2.2 使用


4.2 消息队列

4.2.1 概念和原理

消息队列是另一种标准IPC,当然也大概遵循大部分标准

消息队列,它是存放消息(数据)的队列,而队列是先进先出的线性数据结构

换句话说,我们就是利用这个数据结构 进行进程间的通信

消息队列允许多个进程同时读写消息.由于消息可以定义很多类型,取出时可以指定哪个消息类型取出,所以消息队列解决了共享内存多个进程同时读写时数据混乱的问题,只要把消息标定不同的类型即可

 

 

4.2.2 使用

1)通过ftok获取key

2)通过key 创建/获取 消息队列 ------- msgget        

      参数:

            key - 上一步获取的key

            msgflg - 创建标志和权限

                        IPC_CREAT|0666

            成功返回消息队列ID,失败返回-1

    3)把消息 存入队列    /    从队列中取出 ----------- msgsnd/msgrcv

         

         参数:

            msqid - 消息队列ID

            msgq - 消息首地址

            msgsz - 消息长度(消息数据的长度)

            msgtyp - 用来指定接收什么类型的消息(仅仅接收消息时才有)

                0:接收任意类型消息(第一个,先进先出)

                >0:接收类型为msgtyp的特定消息

                <0:接收类型 小于等于 msgtyp绝对值的小,类型从小到大接收

            msgflg - 接收/发送 标识

                0表示阻塞方式操作,接收消息没有消息可接收/发送消息消息队列满了 就会等待直到成功

                IPC_NOWAIT表示非阻塞方式操作,接收消息没有消息可接收/发送消息消息队列满了 直接返回错误

           msgsnd成功返回0,msgrcv成功返回收到消息的消息数据长度,失败都返回-1

 

另外,消息类型在系统中是未定义的,所以程序员需要在代码中自己定义消息的类型,但是必须按照以下形式:

    struct msgbuf {
               long mtype;       /* 消息类型, 必须大于0 */
               char mtext[1];    /* 消息数据, 即存放的数据 */
    };

 

4)不再使用可以删除消息队列 ------- msgctl

      

     参数:

          msqid - 消息队列ID

          cmd - 命令

              IPC_RMID:删除

              IPC_SET:  修改

              IPC_STAT:   获取

           buf - 设置/获取 时 传入/传出 消息队列的信息, 下面是它的数据类型 ,其中可以修改的是uid、gid和mode

           msgctl函数成功返回0,失败返回-1

struct msqid_ds {
               struct ipc_perm msg_perm;     /* Ownership and permissions */
               time_t          msg_stime;    /* 最后发送消息时间 */
               time_t          msg_rtime;    /* 最后接收消息时间 */
               time_t          msg_ctime;    /* 最后修改时间 */
               unsigned long   __msg_cbytes; /* 当前使用消息队列空间大小 (nonstandard) */
               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 supplied to msgget(2) */
               uid_t          uid;         /* Effective UID of owner */
               gid_t          gid;         /* Effective GID of owner */
               uid_t          cuid;        /* Effective UID of creator */
               gid_t          cgid;        /* Effective GID of creator */
               unsigned short mode;        /* Permissions */
               unsigned short __seq;       /* Sequence number */
           };

消息队列发送端代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct MSG{
    long mtype;
    char mtext[100];
};

int main()
{
    //1.获取key
    key_t key = ftok(".",'x');
    if(key==-1){
        perror("ftok");
        exit(-1);
    }

    //2.创建消息队列
    int msqid = msgget(key,IPC_CREAT|0666);
    if(msqid==-1){
        perror("shmget");
        exit(-1);
    }

    //3.发送消息
    struct MSG msg1;
    msg1.mtype = 1;//类型1
    strcpy(msg1.mtext,"liubei");
    int res = msgsnd(msqid,&msg1,sizeof(msg1.mtext),0);
    if(res==-1){
        perror("msgsnd");
        exit(-1);
    }


    msg1.mtype = 2;//类型2
    strcpy(msg1.mtext,"guanyu");
    res = msgsnd(msqid,&msg1,sizeof(msg1.mtext),0);
    if(res==-1){
        perror("msgsnd");
        exit(-1);
    }
    printf("消息发送成功!\n");



    return 0;
}

消息队列接收端代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>

extern int errno;

struct MSG{
    long mtype;
    char mtext[100];
};

int main()
{
    //1.获取key
    key_t key = ftok(".",'x');
    if(key==-1){
        perror("ftok");
        exit(-1);
    }

    //2.获取消息队列
    int msqid = msgget(key,0);
    if(msqid==-1){
        perror("shmget");
        exit(-1);
    }

    //3.接收消息
    struct MSG msg1;
    
    while(1){
        //类型-2,方式非阻塞
        int res = msgrcv(msqid,&msg1,sizeof(msg1.mtext),/*-2*/0,IPC_NOWAIT);
        //接收完成删除消息队列
        if(res==-1&&errno==ENOMSG){
            break;
        }
        else if(res==-1&&errno!=ENOMSG){
            perror("msgrcv");
            exit(-1);
        }
        else{
            printf("消息类型 = %ld,消息内容 = %s\n",msg1.mtype,msg1.mtext);
        }
    }

    msgctl(msqid,IPC_RMID,0);
    printf("消息队列删除成功!\n");

    return 0;
}

输出如下:

liaowenbindeMacBook-Pro:3 liaowenbin$ ./4msg 
消息发送成功!
liaowenbindeMacBook-Pro:3 liaowenbin$ gcc 5msg.c -o 5msg
liaowenbindeMacBook-Pro:3 liaowenbin$ ./5msg 
消息类型 = 1,消息内容 = liubei
消息类型 = 2,消息内容 = guanyu
消息队列删除成功!

 

Logo

更多推荐