进程间通信_05消息队列

一概述

消息队列就是一段有一定格式的内存区,即一个消息的链表,位于内核中,可以把消息看成一条记录,这个记录有特定的格式和优先级。

消息队列的读和写是异步的,发送方不必等到接收方接收,接收方发现没有数据也不用等待。

新的消息总是放在队尾,接收的时候不一定要遵守先进先出的原则,可以根据优先级获取数据

消息队列只有在内核重启或者显示的删除的时候才会被删除掉

二 操作函数

1 创建消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key,              //key值,标识消息队列的唯一性
                   int msgflg);    //设置消息队列的属性。一般为 0666 | IPC_CREAT
//返回值:>0(成功,消息队列的标识符) -1(创建失败,失败信息见errno)

2 创建之后shell查看的方法

ipcs -q | grep -i key

如:ipcs -q | grep -i 4d2   即查看key值为1234(16进程为4d2)的消息队列

3 向消息队列中写入数据

#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
int msgsnd(int msqid,                  //消息队列的标识符
                   const void *msgp,   //包含数据的结构体指针
                   size_t msgsz,       //结构体中数据的长度
                   int msgflg);        //用于设置发送数据时的一些特性
//返回值: 0(写数据成功)  -1(写数据失败,错误信息见errno)

msgp是一个结构体的指针,结构体是由用户定义的,定义的结构应该按照如下格式:

struct msgbuf {
    long mtype;         /* message type, must be > 0 */
    char mtext[1];      /* message data */
};

其中,

msgflg决定发送消息时的一些特性。

比如:默认情况下,如果消息队列中暂时没有空间的话,默认消息队列是会阻塞的。

但,如果msgflg字段赋值为IPC_NOWAIT,则这种情况下会直接返回EAGAIN错误。

4 从消息队列中读取数据

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>
       ssize_t msgrcv(int msqid,                     //消息队列的标识符
                                void *msgp,          //接收消息存放的容器
                                size_t msgsz,        //接收消息的大小
                                long msgtyp,         //接收消息的消息类型
                                int msgflg);         //设置接收消息时的一些特性
//返回值:>0 (成功读取到的数据大小)  -1(失败,错误信息见errno)

其中,

msgtype就是接受的优先级,即结构体msgbuf中的mtype字段。

如果,=0  就从消息队列中的第一个消息取;

>0  就从有相同消息类型的第一个消息开始取;

<0  就从<= abs(msgtype)的第一个消息开始取。

msgflg决定接收消息时的一些特性。

如,当发送过来的消息大小超过接收容器的大小时,默认情况返回失败,errno设置为E2BIG.

但,此时如果msgflg设置为MSG_NOERROR,则会将消息按照接收容器截断并返回成功。

5 消息队列的属性操作函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid,                             //消息队列的标识符
                  int cmd,                        //对消息队列属性的操作
                  struct msqid_ds *buf);          //消息队列的属性
//返回值:0(成功)  -1(失败,失败信息见errno)

其中,

cmd取值如下:IPC_STAT     获取消息队列的属性信息

IPC_SET       设置消息队列的属性信息

IPC_RMID    删除消息队列,并将相关联的读写进程返回错误,errno设置为EIDRM

buf参数是消息属性的结构体指针,结构体定义如下:

struct msqid_ds {
    struct ipc_perm msg_perm;        /* Ownership and permissions */
    time_t msg_stime;                /* Time of last msgsnd(2) */
    time_t msg_rtime;                /* Time of last msgrcv(2) */
    time_t msg_ctime;                /* Time of last change */
    unsigned long __msg_cbytes;      /* Current number of bytes in  queue (non-standard) */
    msgqnum_t msg_qnum;              /* Current number of messages  in queue */
    msglen_t msg_qbytes;             /* Maximum number of bytes  allowed in queue */
    pid_t msg_lspid;                 /* PID of last msgsnd(2) */
    pid_t msg_lrpid;                 /* PID of last msgrcv(2) */
};

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 */
};

消息队列的大小在以下文件中:

/proc/sys/kernel/msgmax    单个消息的最大值         缺省值为 8192

/proc/sys/kernel/msgmnb      单个消息体的容量的最大值  缺省值为 16384

/proc/sys/kernel/msgmni       消息体的数量         缺省值为 16

也可以通过字段 msg_qbytes 修改消息队列的总大小。

6 shell手动删除的方法

ipcrm -q msqid

其中,msqid也可以通过ipcs查看

可以知道这个环境中key值1234(4d2)对应的msqid是32768。

执行ipcrm -q 32768 就可以删除消息队列。

三 使用实例

1 向消息队列写数据

/*************************************************************************
    > File Name: testmsgqueueW.c
    > Author: qiaozp
    > Mail: [email protected]
    > Created Time: 2014-9-19 17:15:09
    > Step: 1 连接消息队列
            2 读数据
 ************************************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <errno.h>
using namespace std;

#define KEY 1234
#define MAX_BUFF_SIZE 512

typedef struct {
    long mtype;
    char mtext[MAX_BUFF_SIZE];
}_msgbuf;

int main()
{
    //1 创建消息队列
    int msgid = 0;
    if((msgid = msgget((key_t)KEY, 0666|IPC_CREAT)) == -1)
    {
        cout << "创建key值为[" << KEY << "]的消息队列失败" << endl;
        return -1;
    }

    _msgbuf buff;
    //2 向消息队列中写数据
    while(1)
    {
        cout << "请输入要放入消息内存中的数据:";
        scanf("%s", buff.mtext);

        if(msgsnd(msgid, (void*)&buff, MAX_BUFF_SIZE, 0) == -1)
        {
            cout << "向key值为[" << KEY << "]的消息队列发送数据失败" << endl;
            return -1;
        }

        if(strncasecmp(buff.mtext, "end", strlen("end")) == 0)
        {
            //结束的时候删除消息队列
            if(msgctl(msgid, IPC_RMID, NULL) == -1)
            {
                cout << "删除key值为[" << KEY << "]的消息队列失败" << endl;
                return -1;
            }
            break;
        }
    }

    return 0;
}

2 从消息队列读取数据

/*************************************************************************
    > File Name: testmsgqueueR.c
    > Author: qiaozp
    > Mail: [email protected]
    > Created Time: 2014-9-19 17:15:28
    > Step: 1 创建消息队列
            2 写数据
            3 end退出
 ************************************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <errno.h>
using namespace std;

#define KEY 1234
#define MAX_BUFF_SIZE 512

typedef struct {
    long mtype;
    char mtext[MAX_BUFF_SIZE];
}_msgbuf;

int main()
{
    //1 创建消息队列
    int msgid = 0;
    if((msgid = msgget((key_t)KEY, 0666|IPC_CREAT)) == -1)
    {
        cout << "创建key值为[" << KEY << "]的消息队列失败" << endl;
        return -1;
    }

    _msgbuf buff;
    //2 向消息队列中写数据
    cout << "开始从消息队列中获取数据,请在服务端输入数据..." << endl;
    while(1)
    {
        if(msgrcv(msgid, (void*)&buff, MAX_BUFF_SIZE, 0, 0) == -1)
        {
            cout << "从key值为[" << KEY << "]的消息队列获取数据失败" << endl;
            return -1;
        }
        cout << "获取到的数据为 : " << buff.mtext << endl;

        if(strncasecmp(buff.mtext, "end", strlen("end")) == 0)
        {
            cout << "退出." << endl;
            break;
        }
    }

    return 0;
}
 

时间: 2024-10-29 10:45:52

进程间通信_05消息队列的相关文章

进程间通信(6) - 消息队列posix

1.前言 本篇文章的所有例子,基于RHEL6.5平台(linux kernal: 2.6.32-431.el6.i686). 2.介绍 消息队列是先进先出FIFO原则. 消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程可以向其中按照一定的规则添加新消息:对消息队列有读权限的进程则可以从消息队列中读走消息.消息队列是随内核持续的. 目前主要有两种类型的消息队列:POSIX消息队列以及System V消息队列,System V消息队列目前被

Linux系统编程——进程间通信:消息队列

消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法,其特点如下: 1)消息队列可以实现消息的随机查询.消息不一定要以先进先出的次序读取,编程时可以按消息的类型读取. 2)消息队列允许一个或多个进程向它写入或者读取消息. 3)与无名管道.命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删除. 4)每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的. 5)消息队列是消息的链表,存放在内存中,由内核维护.只有内核重启或人工删除消息队列时,该消息队列才会被删

linux进程间通信之消息队列

我们已经知道进程通信的方式是有多种的,在上一篇博客中讲述了通过管道实现简单的进程间通信,那么接下来我们看看与之类似的另一种方式,通过消息队列来实现进程间通信. 什么是消息队列 消息队列提供了一种由一个进程向另一个进程发送块数据的方法.另外,每一个数据块被看作有一个类型,而接收进程可以独立接收具有不同类型的数据块.消息队列的好处在于我们几乎可以完全避免同步问题,并且可以通过发送消息屏蔽有名管道的问题.更好的是,我们可以使用某些紧急方式发送消息.坏处在于,与管道类似,在每一个数据块上有一个最大尺寸限

练习--LINUX进程间通信之消息队列MSG

https://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 继续坚持,或许不能深刻理解,但至少要保证有印象. ~~~~~~~~~~~~~~ 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.作为早期unix通信机制之一的信号能够传送的信息量有限,后来虽然POSIX 1003.1b在信号的实时性方面作了拓广,使得信号在传递信息量方面有了相当程度的改进,但是信号这种通信方式更像"即时"的通信方式,它要求接受信号的进程在某

[转]Linux进程间通信——使用消息队列

点击此处阅读原文 另收藏ljianhui的专栏初学Linux 下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信--使用命名管道 一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息队列与命名管道一样,每个数据块都有一个最大长度的

Linux进程间通信——使用消息队列

下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信--使用命名管道 一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制. Linux用宏MSGMAX和MSGMNB来限制一条消息

Linux进程间通信(消息队列/信号量+共享内存)

写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系统调用来支持,本实验要求学生首先查找资料了解所选用操作系统平台上用于进程通信的系统调用具体形式,然后使用该系统调用编写程序进行进程间的通信,要求程序运行结果可以直观地体现在界面上.在此基础上查找所选用操作系统平台上支持信号量机制的系统调用具体形式,运用生产者与消费者模型设计实现一个简单的信箱,该信箱

进程间通信之消息队列通信

概念 消息队列 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值 消息队列也有管道一样的不足,就是每条消息的最大长度是有上限的(MSGMAX),每个消息队列的总字节数(内核缓冲上限)是有上限的(MSGMNB),系统上消息队列的总数(消息条目数)也有一个上限(MSGMNI) 对比: 管道 消息 流管道 有边界 先进先出 可以后进入.先出来 消息大小三大限制 cat /proc/sys/kernel/msgmax最

进程间通信之消息队列

什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制. 相关接口函数 ftok函数 头文件 #include <sys/types.h> #include <sys/ipc.h> 函数原型 key_t ftok( const char * fname, int id