简介

这篇笔记中介绍了消息队列的基本知识和Posix消息队列。这篇笔记主要学习记录System V消息队列,并对比两个消息队列。

System V消息队列是更早的一个消息队列的实现。Posix消息队列接口简单,但是缺陷之一是只能获取最高优先级的消息;而System V队列与之的最大的区别就是在消息类型和优先级上更加灵活。System V消息队列也是随内核持续的,而且也是链式结构实现的。

基本操作

创建或者获取消息队列:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
  • key:可以是IPC_PRIVATE或者ftok()函数返回的参数。
  • msgflg:指定创建的参数,第一次创建使用IPC_CREAT,其余的都是按照比特位或进行操作。如果IPC_CREAT | IPC_EXCL,则参照open函数的笔记,两者用法一致。
  • Return Value:成功返回消息队列的id;失败返回-1,并设置errno

发送消息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • msqidmsgget返回的消息队列标识符
  • msgp:需要发送的消息,该消息具有以下结构:
    struct msgbuf {long mtype;char mtext[msgsz];
    };
    
    • mtype:表示消息的类型,必须是正数!!!
    • mtext:表示存储消息的数组,由参数指定大小
  • msgsz:指定消息存储数据区的大小
  • msgflg:指定接收的行为参数。正常设置为0,如果是IPC_NOWAIT,则立刻返回。
  • Return Value:成功返回0;失败返回-1,并设置错误码errno

接收消息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *prt, size_t length, long type, int flag);
  • msgqid:消息队列的标识符
  • ptr:存储消息的地址
  • length:缓冲区数据部分的长度,参照msgsnd函数介绍
  • type:指定消息的返回类型,见下文
  • flag:指定接受行为的参数,见下文
  • Return Value:接收消息的字节数,不包括长整型占用的字节

在这里着重介绍type,有3个取值:

  • 0:返回队列中第一个消息
  • 大于0:返回类型为type的第一个消息
  • 小鱼0,返回类型值小于等于type绝对值的最小的一个消息

介绍flag参数:

操作消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • msqid:消息队列标识符
  • cmd:命令参数
  • 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 inqueue (nonstandard) */msgqnum_t       msg_qnum;     /* Current number of messagesin queue */msglen_t        msg_qbytes;   /* Maximum number of bytesallowed in queue */pid_t           msg_lspid;    /* PID of last msgsnd(2) */pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
};

其中ipc_perm结构如下:

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

命令参数:

  • IPC_STAT:拷贝消息队列的命令参数到buf
  • IPC_SET:设置队列参数,具体参照手册。
  • IPC_RMID:移除整个消息队列,如果有写入或者读取,会得到EIDRM错误
  • IPC_INFO:返回系统级别的消息队列的限制,参考手册
  • MSG_INFO:类似IPC_INFO,但是有几个域排除掉,参考手册
  • MSG_STAT:与IPC_STAT类似,区别参考手册

代码实例

实现一个和上一篇笔记的Posix队列,实现一个类似的功能。一个服务端接收,多个客户端发送消息。暂时有些小的bug。

注意一个点,因为System V消息队列是跟随内核同步的,所以应该可以获取一个全局的队列标识符。这通过ftok()系统调用实现。

客户端:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <signal.h>
#include <cstdio>
#include <unistd.h>
#include <strings.h>
#include <wait.h>
#include <vector>
#include <time.h>const int MAX_BUFFER_SIZER = 50;
const int CLIENT_NUM = 10;bool stop_client = false;
key_t msqkey;
int msqid;
std::vector<pid_t> childProcess;struct usermsg {long mtype;char mtext[MAX_BUFFER_SIZER];
};int register_signal(int sig, void(*sig_handler)(int));
void sig_int(int sig);
void child_process();
void sig_int_child(int sig);inline void handle_error(const char *err) {perror(err);exit(EXIT_FAILURE);
}int main() {srand(time(0));key_t msqkey = ftok("/tmp/msg_example", 1);int msqid = msgget(msqkey, IPC_CREAT);if (msqid < 0) {handle_error("msgget() error\n");}for (int i = 0; i < CLIENT_NUM; ++i) {pid_t pid = fork();if (pid == 0) {child_process();exit(EXIT_SUCCESS);} else {childProcess.push_back(pid);}}if (register_signal(SIGINT, sig_int) < 0) {handle_error("register_signal() error\n");}wait(nullptr);puts("stop all client");exit(EXIT_SUCCESS);
}void child_process() {int n = 5;register_signal(SIGINT, sig_int_child);usermsg msg;while (!stop_client) {msg.mtype = rand() % 2;if (msg.mtype == 0) {snprintf(msg.mtext, 50, "msgtype = 0");} else {snprintf(msg.mtext, 50, "msgtype = 1");}if (msgsnd(msqid, (usermsg *) &msg, 50, 0) < 0) {handle_error("msgsnd() error\n");}sleep(rand() % 3);if (--n <= 0) {return;}}
}int register_signal(int sig, void(*sig_handler)(int)) {struct sigaction sa;bzero(&sa, sizeof(sa));sa.sa_handler = sig_handler;sa.sa_flags = SA_RESTART;return sigaction(sig, &sa, nullptr);
}void sig_int(int sig) {if (sig != SIGINT) {return;}for (const auto &it: childProcess) {kill(it, SIGINT);}puts("main proess gets stop signal");
}void sig_int_child(int sig) {if (sig != SIGINT) {return;}printf("client %d end...\n", getpid());stop_client = true;
}

服务器:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <signal.h>
#include <cstdio>
#include <unistd.h>
#include <strings.h>const int MAX_BUFFER_SIZER = 50;
bool stop_server = false;struct usermsg {long mtype;char mtext[MAX_BUFFER_SIZER];
};void sig_int(int sig);inline void handle_error(const char *msg) {perror(msg);exit(EXIT_FAILURE);
}int main() {// 创建一个消息队列key_t msqkey = ftok("/tmp/msg_example", 1);  // 获取全局标识符int msqid = msgget(msqkey, IPC_CREAT);if (msqid < 0) {handle_error("msgget() error\n");}struct sigaction sa;bzero(&sa, sizeof(sa));sa.sa_handler = sig_int;sa.sa_flags = SA_RESTART;if (sigaction(SIGINT, &sa, nullptr) < 0) {handle_error("sigaction() error\n");}usermsg msg;msg.mtype = 1;while (!stop_server) {ssize_t ret = msgrcv(msqid, (usermsg *) &msg, MAX_BUFFER_SIZER, msg.mtype, 0);printf("get message %s, type = %ld", msg.mtext, msg.mtype);sleep(1);}exit(EXIT_SUCCESS);
}void sig_int(int sig) {if (sig != SIGINT) {return;}puts("stop server...");stop_server = true;
}

System V消息队列相关推荐

  1. linux进程间通信:system V消息队列

    文章目录 基本介绍 编程接口 代码实例 消息队列的发送和接收 消息队列中的消息对象的属性控制 基本介绍 支持不同进程之间以消息(messages)的形式进行数据交换,消息能够拥有自己的标识,且内核使用 ...

  2. System V 消息队列

    一.System V 消息队列 有一个队列,队列存放各种消息.每个进程可以把数据封存在消息中,再放入队列.每个进程都可以拿到消息队列,再从中取出/放入消息. 消息队列也有管道一样的不足,就是每个消息的 ...

  3. Linux网络编程之System V消息队列

    System V消息队列函数: #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int ...

  4. System V 消息队列概念以及相关函数(msgget、msgsnd、msgrcv、msgctl)介绍

    System V 消息队列 消息队列是半双工的通信方式 1.1 创建一个消息队列 消息队列的特点:消息只能一条的读取,不能多读取,也不能少读取,每条消息有一个类型,可以按照消息的类型读取 创建或者打开 ...

  5. (P26)system v消息队列:msgsnd函数 ,msgrcv函数

    文章目录 1.msgsnd函数 2.msgrcv函数 1.msgsnd函数 功能:把一条消息添加到消息队列中原型:int msgsnd(int msqid, const void *msgp, siz ...

  6. 06.System V 消息队列

    1.概述 System V消息队列使用消息队列标识符(message queue identifier)标识.具有足够特权的任何进程都可以往一个给定队列放置一个消息,具有足够特权的任何进程都可以从一个 ...

  7. system V消息队列的使用

    最近在学习网络,主要是<UNIX网络编程>这本书,现在给大家分享以下我在学习消息队列这一部分的心得和体会,如果有不足之处希望大家批评指正. 大家知道linux中支持Posix消息队列和Sy ...

  8. Linux进程通信之System V消息队列

    System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...

  9. 细说linux IPC(十):system V 消息队列

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类 ...

最新文章

  1. AWS云使用100条宝贵经验分享
  2. Android APK文件学习调研
  3. java 对字符串中的数值排序
  4. 【转】(六)unity4.6Ugui中文教程文档-------概要-UGUI Animation Integration
  5. PAT_B_1089_Java(20分)
  6. Windows 7 下右键发送到菜单项没了
  7. 《Reids 设计与实现》第十七章 发布与订阅
  8. Hello China操作系统的安装和使用
  9. 公务员可以做哪些合法正规的兼职
  10. 超市不同时段人流量统计分析
  11. ubuntu安装中文输入法fcitx
  12. OFDM子载波频率 知乎_频谱中射频干扰信号流化、分析与回放
  13. CMOS模拟集成电路设计 吴金 学习记录2
  14. napi娃娃_第二十九章 干妈
  15. 有多少程序员干到35岁,那么其他人去干什么了?
  16. 关注公众号回复图片php,公众号被关注回复可以回复文字加图片消息吗? | 微信公众号指南...
  17. The projects in the reactor contain a cyclic reference
  18. 【tensorflow学习笔记】
  19. 核心交换机的链路聚合、冗余、堆叠、热备份如何理解与配置
  20. 第五章--第三节:设计复用模式(pattern)

热门文章

  1. hun暑期实训 最大报销额(01背包) 关于动态内存分配的new与delete
  2. nlp-tutorial代码注释笔记
  3. 【计算机网络】ACL工作原理及标准
  4. Chrome禁止http自动转为https
  5. one stage 与two stage解释
  6. Linux下压缩、解压缩、效率,linux tar bz、bz2、gz、zip
  7. LeetCode 340. 至多包含 K 个不同字符的最长子串
  8. List 按照中文姓名升序排列
  9. 编译程序 解释程序
  10. 红皮书--EOF与BOF