前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux进程间通信——消息队列(一)

Linux进程间通信——消息队列(一)

作者头像
用户5908113
发布2020-06-09 12:01:38
3K0
发布2020-06-09 12:01:38
举报
文章被收录于专栏:Pou光明

我学习一个东西,喜欢先从整体上了解框架,然后再了解所学习的东西是框架中的哪一细分部分。今天就聊一聊Linux系统进程之间的通信。

程序环境:ubuntu16.04 x_64 虚拟机

一、站得高,望得远

有三种IPC(进程间通讯)我们称作XSI IPC,即消息队列、信号量和共享内存

1. XSI IPC

①POSIX标准 Portable Operating System Interface(可移植操作系统接口)

②Single UNIX Specification是POSIX的超集

③X/Open System Interface(XSI IPC)

符合Single UNIX规范的系统的核心应用程序编程接口

有点儿蒙圈吧,正常正常~

个人理解:听说过POSIX多线程程序设计吧,就是符合①的可移植操作系统接口的多线程设计,然后②又是①的超集,再然后③是符合②的......可能很多人就是因为这些才不想学一些东西吧,不过这些不清楚也没多大关系

2. 进程间通信分类

进程间数据通信必须通过内核,因为不同进程的用户地址空间是不同的,他们各自的全局变量是不可见的。所以他们通过在内核地址上开辟出一段空间来进行数据传输。

进程间通信根据是否在同一台主机上进行通信可分为无名管道和有名管道(FIFO),消息队列、信号量和共享内存这些都是只能在同一台主机上进行通信的

Socket和Streams(这个没接触过)是可以在不同主机上进行进程通讯的。

3. 进程间通信之管道简介

①无名管道

②有名管道

无名管道的限制:半双工

两个进程需要有公共祖先

有名管道举例:当在终端连续使用两个命令时,一条命令的输出通过管道作为另一条命令的输入。

二、XSI IPC的使用与注意事项

1. 标识符和Key

每个内核中的IPC结构(消息队列、信号量、共享内存)都用一个非负整数的标识符来进行调用。如,当使用消息队列发送或接收消息队列时,需要知道队列标识符。

标识符是IPC内部的名称,在外部通信时使用Key作为标识符,每个IPC对象都与一个Key相关联。

2. 新建Key的方法及注意事项

get函数的两个参数分别是Key和一个整型flag(之后会介绍get函数)

①Key是IPC_PRIVATE

②Key当前未与特定的IPC结构相结合,并且flag中指定了IPC_CREAT位

③ftok(暂不具体介绍)

当访问已存在的队列时,Key值必须与创建队列时指定的Key值相同,且不应指定IPC_CREAT

注意:①为了访问一个现存的队列,决不能指定IPC_PRIVATE作为Key,因为它总是用于创建一个新队列。

②如果希望新建一个消息队列,而且要确保不是引用具有同一标识符的现有的消息队列,需在flag中指定IPC_CREAT和IPC_EXCL。这样,如果消息队列已经存在则返回值会报错。

3. 三种形式XSI IPC结构限制

我的系统默认限制如下:

4. 优点和缺点

XSI IPC的主要问题是:IPC结构是在系统范围内起作用的,没有引用计数。这点可以类比C++的智能指针。例如:如果进程创建 了一个消息队列,并在队列中放入了几条消息,然后进程终止,但是该消息队列及其内容并不会被删除。

当以下情况出现时消息队列才不会继续存在系统中:

①某个进程调用msgrcv或msgctl读取或删除消息队列

②某个进程执行ipcrm(1)命令删除息队列

与管道相比,最后一个访问管道的进程结束时,管道就彻底被删除了(可与智能指针类比)。

5. 程序通信例子

①Send:

代码语言:javascript
复制
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>

#define MAX_TEXT 512
struct msg_st
{
  long int msg_type;
  char text[MAX_TEXT];
};

int main()
{
  int running = 1;
  struct msg_st data;
  char buffer[BUFSIZ];
  int msgid = -1;

  //建立消息队列
  msgid = msgget((key_t)1234, 0666 | IPC_CREAT | IPC_EXCL);
  if(msgid == -1)
  {
    fprintf(stderr, "msgget failed with error: %d\n", errno);
    exit(EXIT_FAILURE);
  }

  //向消息队列中写消息,直到写入end
  while(running)
  {
    //输入数据
    printf("Enter some text: ");
    fgets(buffer, BUFSIZ, stdin);
    data.msg_type = 1;    //注意2
    strcpy(data.text, buffer);
    //向队列发送数据
    if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
    {
      fprintf(stderr, "msgsnd failed\n");
      exit(EXIT_FAILURE);
    }

    printf("You wrote: %s\n",data.text);

    //输入end结束输入
    if(strncmp(buffer, "end", 3) == 0)
      running = 0;
    sleep(1);
  }
  exit(EXIT_SUCCESS);
}

②Rcv:

代码语言:javascript
复制
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>

struct msg_st
{
  long int msg_type;
  char text[BUFSIZ];
};

int main()
{
  int running = 1;
  int msgid = -1;
  struct msg_st data;
  long int msgtype = 0; //注意1

  //建立消息队列
  //msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
  msgid = msgget((key_t)1234, 0666);
  if(msgid == -1)
  {
    fprintf(stderr, "msgget failed with error: %d\n", errno);
    exit(EXIT_FAILURE);
  }
  //从队列中获取消息,直到遇到end消息为止
  while(running)
  {
    if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)
    {
      fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
      exit(EXIT_FAILURE);
    }
    printf("You wrote: %s\n",data.text);
    //遇到end结束
    if(strncmp(data.text, "end", 3) == 0)
      running = 0;
  }
  //删除消息队列
  if(msgctl(msgid, IPC_RMID, 0) == -1)
  {
    fprintf(stderr, "msgctl(IPC_RMID) failed\n");
    exit(EXIT_FAILURE);
  }
  exit(EXIT_SUCCESS);
}

③程序运行效果

发送效果:

接收效果:

运行发送程序,根据提示输入字符串,接收端会收到字符,输入end消息队列

终止。

三、小结

程序就是网上最流行的例子,做了微小的改动,下面想几个问题:

①发送和接收可以对同一个Key多次使用不同的进程访问么?如果可以效果是什么样的,一对多还是多对一?多次访问属于正常操作么?

②使用什么方式让发送端与接收端都知道Key值呢?

③下次具体介绍api时还有其他精彩的用法

参考书籍 《UNIX环境高级编程第三版》

阅读一手资料,多思考,还是挺好的。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Pou光明 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 CMQ 版
消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档