Linux编程基础 5.2:消息队列

3 消息队列

  • 消息队列的本质是一个存放消息的链表,该链表由内核来维护。一个消息队列由一个标识符(即队列key)来标识。
  • 消息队列的通信机制传递的数据具有某种结构,而不是简单的字节流;
  • 向消息队列中写数据,实际上是向这个数据结构中插入一个新结点;
  • 从消息队列中读数据,实际上是从这个数据结构中删除一个结点;
  • 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法;
  • 消息队列具有和管道一样的不足,每个数据块的最大长度是有上限的,系统上全体队列的最大总长度也是有上限的。

在这里插入图片描述
使用消息队列实现进程间通信的步骤如下:

  • (1)创建消息队列;
  • (2)发送消息到消息队列;
  • (3)从消息队列中读取数据;
  • (4)删除消息队列。

Linux内核提供了4个系统调用:

int msgget(key_t key, int msgflg); //创建消息队列,返回值为该队列号
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);//发送消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);//接受信息,msgtyp需要指明接受的数据type
key_t ftok(const char *pathname, int proj_id);//为队列随机附加key,pathename为路径,id号可随意(1-255)
int msgctl(int msqid, int cmd, struct msqid_ds *buf);//对指定消息队列进行控制

3.1 用户消息缓冲区

无论发送进程还是接收进程,都需要在进程空间中用消息缓冲区来暂存消息。该消息缓冲区的结构定义如下:

struct msgbuf{long int msgtype;		//消息类型anytype data;			//要发送的数据,可以为任意类型
};

通过msgtype区分数据类型,同过判断msgtype,是否为需要接收的数据;
data为存放消息的正文。

3.2 msgget函数

#include <sys/msg.h>int msgget(key_t key, int msgflg); //创建消息队列,返回值为该队列号

功能:创建一个消息队列或获取一个已经存在的消息队列。

参数说明

  • key:传入参数,消息队列的键值,通常为一个整数,若键值为IPC_PRIVATE,将会创建一个只能被创建消息队列的进程读写的消息队列;
  • msgflg:类似于open函数中标志位的功能,用于设置消息队列的创建方式或权限,通常是一个9位的权限与如下值进行位操作后获得:
    – msgflg = mask | IPC_CREAT,若内核中不存在指定消息队列,则它会被创建;若已存在,则获取该消息队列;
    – msgflg = mask | IPC_CREAT | IPC_EXCL时,若消息队列不存在,则它会被创建;若已存在,则msgget函数调用失败,返回-1,并设置errno为EEXIST。

返回值说明

  • 成功:返回消息队列的标识符;
  • 不成功:返回-1并设置errno。

3.3 msgsnd函数

#include <sys/msg.h>int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);//发送消息

功能:向指定消息队列发送一个消息;如果msgflg = 0,调用函数的进程会被挂起,直到消息写入消息队列为止。

参数说明

  • msqid:消息队列标识符,即msgget函数调用成功后的返回值;
  • msgp:指向消息缓冲区的指针;
  • msgsz:消息中数据的长度,这个长度不包括长整型成员变量的长度;
  • msgflg:标志位,可以设置为0或IPC_NOWAIT。

返回值说明

  • 成功:返回消息队列的标识符;
  • 不成功:若消息队列已满或系统中消息数量达到上限,返回-1并设置errno。

3.4 msgrcv函数

#include <sys/msg.h>ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);//接受信息,msgtyp需要指明接受的数据type

功能:从消息队列中读取消息,被读取的消息会从消息列表中移除。

参数说明

  • msqid:消息队列标识符,即msgget函数调用成功后的返回值;
  • msgp:指向所读取消息的结构体指针;
  • msgsz:消息中数据的长度,这个长度不包括长整型成员变量的长度;
  • msgtyp:从消息队列中读取的消息类型:
    – msgtyp = 0:获取队列中的第一个可用消息;
    – msgtyp > 0:获取队列中与该值类型相同的第一个消息;
    – msgtyp < 0:获取队列中消息类型小于或等于其绝对值的第一个消息。
  • msgflg:标志位:
    – msgflg = 0:进程将阻塞等待消息的读取;
    – msgflg = IPC_NOWAIT:进程未读取到指定消息时将立刻返回-1。

返回值说明

  • 成功:返回消息队列的标识符;
  • 不成功:返回-1并设置errno。

3.5 msgctl函数

#include <sys/msg.h>
#include <sys/ipc.h>int msgctl(int msqid, int cmd, struct msqid_ds *buf);//对指定消息队列进行控制
//内核为每个消息队列维护一个msqid_ds结构,用于消息队列的管理
struct msqid_ds {struct ipc_perm msg_perm;	//所有者和权限标识time_t msg_stime;    		//最后一次发送消息的时间time_t msg_rtime;    		//最后一次接收消息的时间time_t msg_ctime;			//最后改变的时间unsigned long __msg_cbytes;	//队列中当前数据字节数msgqnum_t msg_qnum;			//队列中当前消息数msglen_t msg_qbytes;		//队列中允许的最大字节数pid_t msg_lspid;			//最后发送消息的进程pidpid_t msg_lrpid;			//最后接收消息的进程pid
};

功能:对指定消息队列进行控制。

参数说明

  • msqid:消息队列标识符,即msgget函数调用成功后的返回值;
  • cmd:消息队列的处理命令:
    – cmd = IPC_RMID:从系统内核中删除指定命令,使用命令ipcrm -q id可实现同样的功能;
    – cmd = IPC_SET:若进程有权限,将内核管理的消息队列的当前属性值设置为参数buf各成员的值;
    – cmd = IPC_STAT:将内核所管理的消息队列的当前属性值复制给参数buf。
  • buf:一个缓冲区,用于传递属性值给指定消息队列或从指定消息队列中获取属性值,其功能视cmd而定。

返回值说明

  • 成功:返回消息队列的标识符;
  • 不成功:返回-1并设置errno。

【案例1】使用消息队列实现不同进程间的通信。

  • msgsend.c:消息发送端
  • msgrcv.c:消息接收端
msgrcv.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st{long int my_msg_type;char anytext[MAX_TEXT];
};
int main(){int tempIdx = 1;int tempMsgid;struct my_msg_st tempData;long int tempMsgToRcv = 0;//rcv msgtempMsgid = msgget((key_t)1000, 0664 | IPC_CREAT);//获取消息队列if (tempMsgid == -1){perror("msgget err");exit(-1);}//of ifwhile (tempIdx < 5){//接收消息if (msgrcv(tempMsgid, (void*)&tempData, BUFSIZ, tempMsgToRcv, 0) == -1){perror("msgrcv err");exit(-1);}//of if//打印消息printf("msg type:%ld\n", tempData.my_msg_type);printf("msg content is:%s", tempData.anytext);tempIdx ++;}//of while//删除消息队列if (msgctl(tempMsgid, IPC_RMID, 0) == -1){perror("msgctl err");exit(-1);}//of ifexit(0);
}//of main
msgsend.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#define MAX_TEXT 512
//消息结构体
struct my_msg_st{long int my_msg_type;       				//消息类型char anytext[MAX_TEXT];     				//消息数据
};
int main() {int tempIdx = 1;int tempMsgid;struct my_msg_st tempData;char tempBuf[BUFSIZ];						//设置缓存变量tempMsgid = msgget((key_t)1000, 0664 | IPC_CREAT);//创建消息队列if (tempMsgid == -1){perror("msgget err");exit(-1);}//of ifwhile (tempIdx < 5){							//发送消息printf("enter some text:");fgets(tempBuf, BUFSIZ, stdin);tempData.my_msg_type = rand() % 3 + 1;        	//随机获取消息类型strcpy(tempData.anytext, tempBuf);//发送消息if (msgsnd(tempMsgid, (void*)&tempData, sizeof(tempData), 0) == -1){perror("msgsnd err");exit(-1);}//of iftempIdx ++;}//of whilereturn 0;
}//of main
  • BUFSIZ:Linux系统定义在stdio.h的宏,表示默认缓冲区大小;

3.6 键值和标识符

  • 键值(ID):ID是msgget函数的返回值,一个非负整数,属于进程间通信的内部名,用来确保使用同一个消息队列。内部名即在进程内部使用,是消息队列在进程级别的唯一标识,这样的标识方法是不能支持进程间通信的。

  • 标识符(key): key是实现进程与消息队列关联的关键,属于进程间通信的外部名,是消息队列在内存级别的唯一标识。当多个进程,针对同一个key调用msgget函数,这些进程得到的ID其实是标识了同一个进程间通信的结构。多个进程间就可以通过这个进程间通信的结构进行通信。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/507419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python tab和空格混用_Python编程常见十大错误,看完你自己都笑了!

关注并置顶【柠檬班】的小哥哥小姐姐胸有成“猪”使用python会出现各种各样的错误&#xff0c;以下是Python常见的错误以及解决方法。01 ValueErrorValueError: ‘Conv2d_1a_33’ is not a valid scope name其实这就是命名错误的问题&#xff0c;如果仔细看“”是我在中文下打的…

Linux编程基础 5.3:信号量

4 信号量 信号量是专门用来解决进程同步与互斥问题的一种通信机制&#xff0c;它与信号无关&#xff1b;不同于管道、FIFO以及消息队列&#xff0c;一般不用来传输数据&#xff1b;信号量包括&#xff1a;表示资源数量的非负整型变量、修改信号量的原子操作P和V、该信号量下等…

谷歌浏览器外贸版_针对谷歌SEO,你有哪些值得推荐的工具、插件、网站、app,或者技巧分享?...

接触并了解谷歌SEO也有3年了&#xff0c;这3年来&#xff0c;一直钻研这块技术和工具&#xff0c;今天刚好看到这个问题&#xff0c;就分享下。目前谷歌SEO主要分3大块&#xff0c;站内SEO(On page seo&#xff0c;做好站内优化)&#xff0c;站外SEO(off page seo 主要是外链)&…

hadoopsdk使用_hadoop部署使用问题及解决

在cygwin环境中填写路径信息时务必注意将“\”替换为“/”。hadoop文件夹名称不能包含“-”&#xff0c;比如“hadoop-2.4.0”会出错。在cygwin环境中尽管“C:\abc”和“/cygdrive/c/abc”都可以被正确识别&#xff0c;但某些软件会将前者识别为相对路径&#xff0c;从而出现错…

Linux编程基础 5.4:共享内存

5 共享内存 共享内存允许两个或多个进程访问给定的同一块存储区域。它是效率最高的一种进程通信方式&#xff0c;节省了不同进程间多次读写的时间&#xff1b;在写进程的操作尚未完成时&#xff0c;不应有进程从共享内存中读取数据。共享内存自身不限制对共享内存的读写次序&a…

升级浏览器_微软IE11浏览器 最后的升级机会

微软IE10浏览器将很快退出支持&#xff0c;许多Windows用户将没有任何安全或非安全更新&#xff0c;免费或付费辅助支持选项或在线技术内容等。幸运的是&#xff0c;微软正在为Windows用户提供升级到IE11的最后机会&#xff0c;目前IE11仅次于Firefox浏览器&#xff0c;这是互联…

jq如何获取选中option的值_【分享】如何获取变量token的值

一.什么是token客户端使用用户名跟密码请求登录服务端收到请求&#xff0c;去验证用户名与密码验证成功后&#xff0c;服务端会签发一个 Token&#xff0c;再把这个 Token 发送给客户端客户端收到 Token 以后可以把它存储起来&#xff0c;比如放在 Cookie 里或者 LocalStorage …

Linux编程基础 6.1:线程操作

1 线程操作 创建线程 挂起线程 终止线程 其它操作 1.1 创建线程 #include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); 功能&#xff1a;创建线程&#xff1b;线程调用pthread_crea…

灯效控制器和rgb控制器_更具个性的RGB风扇,机箱里的魔术师,九州风神MF120GT开箱...

写在前面不知道在2020年还有多少人会自己装机&#xff0c;相信喜欢个性的DIY玩家还是会陆陆续续跳进这个不小的坑。装机的乐趣在哪里&#xff0c;除了几大硬件&#xff0c;显然个性的灯效才是装机的灵魂。在光污染的道路上&#xff0c;普通的光环&#xff0c;光面等风扇&#x…

华为交换机ssh思科交换机_华为交换机SSH(stelnet)配置实例教程

Stelnet(安全telnet)登陆也成为shh(sercure shell,安全外壳)登陆-----------必要配置---------------1、先根据加密算法生成秘钥对,用于传输数据时加密保护&#xff0c;保存在交换机中但不保存在配置文件中[Huawei]rsa local-key-pair create或[Huawei]dsa local-key-pair crea…

Linux编程基础 6.2:线程同步

2 线程同步 线程同步中的“同步”与生活中大家认知的“同步”略有不同&#xff0c;“同”不指同时&#xff0c;其主旨在于协同步调&#xff0c;按预定的先后次序执行线程&#xff1b;之所以需要实现线程同步&#xff0c;是因为若不对线程的执行次序加以控制&#xff0c;可能会…

电脑开两个微信_电脑怎么登录两个微信

1/4下载并安装微信电脑客户端&#xff0c;保证这台电脑没有登陆微信2/4就像正常打开微信一样&#xff0c;不过不是双击&#xff0c;而是快速连点四次3/4我们可以看到有两个微信登陆界面4/4用两个不同的账号进行扫码登陆即可

idea 查询项目代码行数_idea统计代码行数Statistic的步骤详解

idea统计代码行数Statistic的步骤详解idea统计代码行数可以用到插件&#xff1a;Statistic。步骤&#xff1a;File→Settings进入Plugins点击Marketplace搜索Statistic 安装蓝框标出的插件重启idea后就可以看到效果了(图是拿的别人的&#xff0c;基本就是这效果)如果没有下…

Linux编程基础 7.1:套接字通信流程及编程接口

1 socket通信流程 2 socket编程接口 Linux系统中常用的socket网络编程接口有&#xff1a; socket()bind()listen()accept()connect()send()recv()close()其中connect()与send()为客户端专用接口&#xff1b;bind()、listen()、accept()及recv()为服务器端专用接口&#xff1b…

cad2016中选择全图字体怎么操作_cad教程分享CAD中如何删除顽固图层?

Autocad教程公众号&#xff0c;专注于cad教程、cad教程视频的分享&#xff0c;欢迎关注&#xff0c;下载你所需的教程资源&#xff01;如你还未关注&#xff0c;请点击文章标题下方蓝色字体的"Autocad教程"进行关注。cad教程分享-CAD中如何删除顽固图层&#xff1f;方…

python开启多个端口服务_python bottle使用多个端口(多个进程)提高并发

我的程序是用python结合bottle框架写的&#xff0c;但bottle自带wsgi原本只是单进程单线程运行模式(Bottle 默认运行在内置的 wsgiref 服务器上面。这个单线程的 HTTP 服务器在开发的时候特别有用&#xff0c;但其性能低下&#xff0c;在服务器负载不断增加的时候也许会是性能瓶…

Linux编程基础 7.2:服务器和客户端编程案例

1 网络字节序 大端模式&#xff1a;若将数据的高字节保存在内存的低地址&#xff0c;将数据的低字节保存在内存的高地址&#xff1b; 小端模式&#xff1a;若将数据的高字节保存在内存的高地址&#xff0c;将数据的低字节保存在内存的低地址。 网络数据流&#xff1a;大端模式…

div 隐藏_div的position属性

如果你想把div放到合适的位置&#xff0c;请看看这篇文章。<!-- div的position属性--><html><style>.red{height:100px;background:red;}.green{height:100px;background:green;position:relative;left:50px;top:50px;}.black{height:100px;background:black…

苹果笔记本python怎么换行_python怎么换行,我的换行就是执行啊

展开全部首先运行终端或者cmd命令行(windows下)。e69da5e887aa62616964757a686964616f31333433646338执行python3.5的命令。然后输入如下图所示的内容。这种换行方法也可以在编辑器中进行&#xff0c;这里以vim为例&#xff0c;输入与上图类似的代码&#xff0c;保存为t.py脚本…

Linux编程基础 7.3:套接字本地通信

1 socket本地通信 socket原本是为网络通讯设计的&#xff0c;但后来在socket框架的基础上发展出了一种IPC&#xff08;进程通信&#xff09;机制&#xff0c;即UNIX Domain Socket&#xff0c;专门用来实现使用socket实现的本地进程通信。 本地通信的流程与使用的接口与基于TC…