一、消息队列的特点

1.消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识.
    2.消息队列允许一个或多个进程向它写入与读取消息.
    3.管道和命名管道都是通信数据都是先进先出的原则。
    4.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比FIFO更有优势。

    目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除。

二、相关函数

1. 获得key值

key_t ftok(char *pathname, int projid)

#include <sys/types.h>
#include <sys/ipc.h>
参数:
    pathname:文件名(含路径),通常设置为当前目录“.” 比如projid为'a',则为"./a"文件
    projid:项目ID,必须为非0整数(0-255).

2. 创建消息队列
    int msgget(key_t key, int msgflag)

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
功能:
    用于创建一个新的或打开一个已经存在的消息队列,此消息队列与key相对应。
参数:
    key:函数ftok的返回值或IPC_PRIVATE。
    msgflag:
        IPC_CREAT:创建新的消息队列。
        IPC_EXCL:与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误。
        IPC_NOWAIT:读写消息队列要求无法满足时,不阻塞。
返回值:
    调用成功返回队列标识符,否则返回-1.

在以下两种情况下,将创建一个新的消息队列:
    1、如果没有与键值key相对应的消息队列,并且msgflag中包含了IPC_CREAT标志位。
    2、key参数为IPC_PRIVATE。

3. 消息队列属性控制
    int msgctl(int msqid,  int cmd,  struct msqid_ds *buf)
功能:

 对消息队列进行各种控制操作,操作的动作由cmd控制。
参数:
    msqid:消息队列ID,消息队列标识符,该值为msgget创建消息队列的返回值。
    cmd:
        IPC_STAT:将msqid相关的数据结构中各个元素的当前值存入到由buf指向的结构中.
        IPC_SET:将msqid相关的数据结构中的元素设置为由buf指向的结构中的对应值.
        IPC_RMID:删除由msqid指示的消息队列,将它从系统中删除并破坏相关数据结构.
buf:消息队列缓冲区
     struct msqid_ds {
               struct ipc_perm msg_perm;          /* Ownership and permissions*/
               time_t         msg_stime;                 /* Time of last msgsnd() */
               time_t         msg_rtime;                  /* Time of last msgrcv() */
               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 bytesallowed in queue */
               pid_t          msg_lspid;                  /* PID of last msgsnd() */
               pid_t          msg_lrpid;                  /* PID of last msgrcv() */
                     };

  struct ipc_perm {
               key_t key;                        /* Key supplied to msgget() */
               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 */
                   };

4.发送信息到消息队列
    int msgsnd(int msqid,  struct msgbuf *msgp,  size_t msgsz,  int msgflag)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
功能:

将新消息添加到队列尾端,即向消息队列中发送一条消息。
参数:
    msqid:已打开的消息队列id
    msgp:存放消息的结构体指针。
    msgflag:函数的控制属性。
    消息结构msgbuf为:
    struct msgbuf
    {
         long mtype;//消息类型
         char mtext[1];//消息正文,消息数据的首地址,这个数据的最大长度为8012吧,又可把他看成是一个结构,也有类型和数据,recv时解析即可。
    }
    msgsz:消息数据的长度。
    msgflag:
         IPC_NOWAIT: 指明在消息队列没有足够空间容纳要发送的消息时,msgsnd立即返回。
         0:msgsnd调用阻塞直到条件满足为止.(一般选这个)

5. 从消息队列接收信息
    ssize_t msgrcv(int msqid,  struct msgbuf *msgp,  size_t msgsz,  long msgtype,  int msgflag)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
功能:

从队列中接收消息
参数:
    msqid:已打开的消息队列id
    msgp:存放消息的结构体指针。msgp->mtype与第四个参数是相同的。
    msgsz:消息的字节数,指定mtext的大小。
    msgtype:消息类型,消息类型 mtype的值。如果为0,则接受该队列中的第一条信息,如果小于0,则接受小于该值的绝对值的消息类型,如果大于0,接受指定类型的消息,即该值消息。
    msgflag:函数的控制属性。
    msgflag:
        MSG_NOERROR:若返回的消息比nbytes字节多,则消息就会截短到nbytes字节,且不通知消息发送进程.
        IPC_NOWAIT:调用进程会立即返回.若没有收到消息则返回-1.
        0:msgrcv调用阻塞直到条件满足为止.
在成功地读取了一条消息以后,队列中的这条消息将被删除。

三、相关例子

例1:消息队列之简单收发测试
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

struct msg_buf{
     int mtype;//消息类型
     char data[255];//数据
};

int main(int argc,  char *argv[])
{
      key_t key;
      int msgid;
      int ret;
      struct msg_buf msgbuf;
      //获取key值
      key = ftok(".",  'a');
      printf("key = [%x]\n",  key);

 //创建消息队列
      msgid = msgget(key,  IPC_CREAT|0666);/*通过文件对应*/
      if(msgid == -1)
      {
            printf("creat error\n");
            return -1;
      }

   //以当前进程类型,非阻塞方式发送"test data"到消息队列
      msgbuf.mtype = getpid();
      strcpy(msgbuf.data,  "test data");
      ret = msgsnd(msgid,  &msgbuf,  sizeof(msgbuf.data),  IPC_NOWAIT);
      if(ret == -1)
      {
            printf("send message err\n");
            return -1;
      }

  //以非阻塞方式接收数据
      memset(&msgbuf,  0,  sizeof(msgbuf));
      ret = msgrcv(msgid,  &msgbuf,  sizeof(msgbuf.data), getpid(),  IPC_NOWAIT);
      if(ret == -1)
      {
            printf("receive message err\n");
            return -1;
      }
      printf("receive msg = [%s]\n",  msgbuf.data);
      return 0;
}
例2:进程间消息队列通信
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <string.h>
#include <signal.h>

struct msgbuf{
      int mtype;
      char mtext[100];
};

int main(void)
{
      key_t key;
      pid_t pid;
      int msgid;
      struct msgbuf msg;

 key=ftok(".", 0x01);
      if ( (msgid = msgget(key,  IPC_CREAT|0666)) <0 )
      {
            perror("msgget error");
            exit(1);
      }

 //创建一个进程
      if ( (pid = fork()) < 0 )
      {
            perror("fork error");
            exit(1);
      }
      //子进程收信息
      else if (pid==0)
      {
            while(1)
            {
                  memset(msg.mtext, 0, 100);
                  msgrcv(msgid, &msg, 100, 9, 0);  //receive the msg from 9
                  printf("\receive:%s\n", msg.mtext);
                  fflush(stdout);
            }
            exit(0);
      }
      //父进程发信息
      else
      {
            while(1)
            {
                  memset(msg.mtext, 0, 100);
                  printf("father:");
                  fgets(msg.mtext, 100, stdin);
                  if (strncmp("bye", msg.mtext, 3)==0)//如果前3个字符为bye,则退出
                  {
                        kill(pid, SIGSTOP);
                        exit(1);
                  }
                  msg.mtype=9;//send to 9
                  msg.mtext[strlen(msg.mtext)-1]='\0';
                  msgsnd(msgid, &msg, strlen(msg.mtext)+1, 0);

       sleep(1);    //等待子进程读完数据
            }
      }

return 0;
}

这个程序的缺点为:有发无收,有收无发。可在这2个进程中分别创建2个线程,分别负责收和发,就完成了进程间的通信。

转载自:http://www.jb51.net/article/37412.htm

IPC--进程间通信六(消息队列)相关推荐

  1. IPC 进程间通信方式——消息队列

    消息队列 消息队列是内核中的一个链表 用户进程将数据传输到内核后,内核重新添加一些如用户ID.组ID.读写进程的ID和优先级等相关信息后并打包成一个数据包称为消息 允许一个或多个进程往消息队列中读写消 ...

  2. linux 消息对lie_Linux进程间通信之消息队列总结

    一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符( i d ...

  3. c语言系统编程八:Linux进程间通信之消息队列

    Linux进程间通信之消息队列 一 消息队列概述 二 消息队列的特点 三 消息队列的创建和使用 3.1 获取系统唯一的key值 3.2 创建消息队列 3.3 查看消息队列和删除消息队列的shell命令 ...

  4. linux消息通信无法接收,进程间通信:消息队列有关问题:进程1接收不到进程2的消息...

    进程间通信:消息队列有关问题:进程1接收不到进程2的消息 进程间通信:消息队列有关问题:进程1接收不到进程2的消息 日期:2014-05-16 浏览次数:20365 次 进程间通信:消息队列问题:进程 ...

  5. IPC通信:Posix消息队列的属性设置

    IPC通信:Posix消息队列的属性设置 Posix消息队列的属性使用如下结构存放: struct mq_attr { long mq_flags; /*阻塞标志位,0为非阻塞(O_NONBLOCK) ...

  6. Linux C 进程间的IPC通信 之 消息队列(2)

    Linux C 进程间的IPC通信 之 消息队列 双向通信 代码:(进程1) 1 #include <stdio.h>2 #include <sys/msg.h>3 #incl ...

  7. linux 进程uhxuhao,linux 进程间通信三 消息队列以及实例

    转自 http://blog.csdn.net/liang890319/article/details/8280934 代码来自:嵌入式Linux应用开发标准教程 消息可以理解为写信给某个人,这里在应 ...

  8. System V IPC POSIX IPC(一):消息队列

    System V IPC & POSIX IPC(一):消息队列 消息队列允许进程之间以消息的形式交换数据,是一种常见的进程之间的通信机制. 1. 消息队列的创建 System V IPC: ...

  9. 进程间通信方式(三)-- IPC对象(消息队列、共享内存、信号灯集)

    IPC对象 1. IPC对象 2. 查看IPC对象命令 3. 消息队列 3.1 概念 3.2 相关函数 3.2.1 msgget() 创建或者打开消息队列 3.2.2 ftok() 获取键值 3.2. ...

  10. 【Linux系统编程】进程间通信之消息队列

    00. 目录 文章目录 00. 目录 01. 消息队列概述 02. 消息队列相关函数 03. 消息队列读写操作 04. 测试代码 05. 附录 01. 消息队列概述 消息队列提供了一种在两个不相关的进 ...

最新文章

  1. 北京大学 李胜 计算机,计算机科学技术系汪国平-李胜团队在虚拟现实领域取得系列进展...
  2. node2vec文献出处_详解Node2vec以及优缺点
  3. 预加载显示图片的艺术
  4. ArcGIS Android工程迁移到其他电脑不能打开的问题
  5. 用VS.NET2003制作WEB应用程序的安装包
  6. 让 Hangfire 使用 MongoDB 存储
  7. React开发(274):ant design 时间显示秒
  8. 【手算】逆序数树形计算方法
  9. 孙宇java_[JAVA] 孙宇老师Struts2+Hibernate4+Maven+EasyUI+SpringMvc+Spring+Mybatis+Maven整合课程...
  10. 数组的连续子数组最大和(首尾相连)
  11. pppoe服务器虚拟机,Hyper-V 批量建立虚拟机自动改IP并配置PPPOE拨号
  12. 百度云BaaS体系揭秘,突破共识机制、单机计算和串行处理三大瓶颈
  13. 2018/7/31-zznuoj-问题 A: A + B 普拉斯【二维字符串+暴力模拟+考虑瑕疵的题意-0的特例】...
  14. LINUX下载编译sqlite-jdbc的jar包
  15. 派生类构造函数 创建顺序(阿里笔试题)
  16. vue开发钉钉微应用鉴权失败
  17. catdog matlab,猫狗收养所 - ranjiewen的个人空间 - OSCHINA - 中文开源技术交流社区
  18. windows搭建Qt源码编译、调试环境
  19. Javascript MS题蓄力:
  20. git + 移动端 web 开发

热门文章

  1. 如何升级Linux内核(RHEL/Fedora/CentOS升级内核 Debian/Ubuntu升级内核)
  2. 使用Maven构建Java项目
  3. 数据可视化组件Grafana详细解读--在Docker上安装Grafana管理平台
  4. 分布式系统关注点(21)——构建「易测试」系统的“六脉神剑”
  5. #nginx# 泛解析大量域名的情况下 将不带www的域名,301到与之对应的www前缀的域名...
  6. C#开发笔记之03-为什么选择IsNotXXX方法而不是IsXXX方法?
  7. node yarn_使用Yarn Plug'n'Play摆脱node_modules
  8. 向圣诞老人和他的精灵学习Google Analytics(分析)
  9. 游戏窗口组合键消息失败_5失败的投资组合,以后我在这里
  10. 深入理解html5:语义,标准与样式pdf,深入理解html5语义标准与样式.doc