System V消息队列
简介
这篇笔记中介绍了消息队列的基本知识和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);
msqid
:msgget
返回的消息队列标识符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消息队列相关推荐
- linux进程间通信:system V消息队列
文章目录 基本介绍 编程接口 代码实例 消息队列的发送和接收 消息队列中的消息对象的属性控制 基本介绍 支持不同进程之间以消息(messages)的形式进行数据交换,消息能够拥有自己的标识,且内核使用 ...
- System V 消息队列
一.System V 消息队列 有一个队列,队列存放各种消息.每个进程可以把数据封存在消息中,再放入队列.每个进程都可以拿到消息队列,再从中取出/放入消息. 消息队列也有管道一样的不足,就是每个消息的 ...
- Linux网络编程之System V消息队列
System V消息队列函数: #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int ...
- System V 消息队列概念以及相关函数(msgget、msgsnd、msgrcv、msgctl)介绍
System V 消息队列 消息队列是半双工的通信方式 1.1 创建一个消息队列 消息队列的特点:消息只能一条的读取,不能多读取,也不能少读取,每条消息有一个类型,可以按照消息的类型读取 创建或者打开 ...
- (P26)system v消息队列:msgsnd函数 ,msgrcv函数
文章目录 1.msgsnd函数 2.msgrcv函数 1.msgsnd函数 功能:把一条消息添加到消息队列中原型:int msgsnd(int msqid, const void *msgp, siz ...
- 06.System V 消息队列
1.概述 System V消息队列使用消息队列标识符(message queue identifier)标识.具有足够特权的任何进程都可以往一个给定队列放置一个消息,具有足够特权的任何进程都可以从一个 ...
- system V消息队列的使用
最近在学习网络,主要是<UNIX网络编程>这本书,现在给大家分享以下我在学习消息队列这一部分的心得和体会,如果有不足之处希望大家批评指正. 大家知道linux中支持Posix消息队列和Sy ...
- Linux进程通信之System V消息队列
System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...
- 细说linux IPC(十):system V 消息队列
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类 ...
最新文章
- AWS云使用100条宝贵经验分享
- Android APK文件学习调研
- java 对字符串中的数值排序
- 【转】(六)unity4.6Ugui中文教程文档-------概要-UGUI Animation Integration
- PAT_B_1089_Java(20分)
- Windows 7 下右键发送到菜单项没了
- 《Reids 设计与实现》第十七章 发布与订阅
- Hello China操作系统的安装和使用
- 公务员可以做哪些合法正规的兼职
- 超市不同时段人流量统计分析
- ubuntu安装中文输入法fcitx
- OFDM子载波频率 知乎_频谱中射频干扰信号流化、分析与回放
- CMOS模拟集成电路设计 吴金 学习记录2
- napi娃娃_第二十九章 干妈
- 有多少程序员干到35岁,那么其他人去干什么了?
- 关注公众号回复图片php,公众号被关注回复可以回复文字加图片消息吗? | 微信公众号指南...
- The projects in the reactor contain a cyclic reference
- 【tensorflow学习笔记】
- 核心交换机的链路聚合、冗余、堆叠、热备份如何理解与配置
- 第五章--第三节:设计复用模式(pattern)