消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例
- 格式:docx
- 大小:17.61 KB
- 文档页数:9
第1篇一、实验目的1. 理解进程通信的概念和原理;2. 掌握进程通信的常用机制和方法;3. 能够使用进程通信机制实现进程间的数据交换和同步;4. 增强对操作系统进程管理模块的理解。
二、实验环境1. 操作系统:Linux2. 编程语言:C3. 开发环境:GCC三、实验内容1. 进程间通信的管道机制2. 进程间通信的信号量机制3. 进程间通信的共享内存机制4. 进程间通信的消息队列机制四、实验步骤1. 管道机制(1)创建管道:使用pipe()函数创建管道,将管道文件描述符存储在两个变量中,分别用于读和写。
(2)创建进程:使用fork()函数创建子进程,实现父子进程间的通信。
(3)管道读写:在父进程中,使用read()函数读取子进程写入的数据;在子进程中,使用write()函数将数据写入管道。
(4)关闭管道:在管道读写结束后,关闭对应的管道文件描述符。
2. 信号量机制(1)创建信号量:使用sem_open()函数创建信号量,并初始化为1。
(2)获取信号量:使用sem_wait()函数获取信号量,实现进程同步。
(3)释放信号量:使用sem_post()函数释放信号量,实现进程同步。
(4)关闭信号量:使用sem_close()函数关闭信号量。
3. 共享内存机制(1)创建共享内存:使用mmap()函数创建共享内存区域,并初始化数据。
(2)映射共享内存:在父进程和子进程中,使用mmap()函数映射共享内存区域。
(3)读写共享内存:在父进程和子进程中,通过指针访问共享内存区域,实现数据交换。
(4)解除映射:在管道读写结束后,使用munmap()函数解除映射。
4. 消息队列机制(1)创建消息队列:使用msgget()函数创建消息队列,并初始化消息队列属性。
(2)发送消息:使用msgsnd()函数向消息队列发送消息。
(3)接收消息:使用msgrcv()函数从消息队列接收消息。
(4)删除消息队列:使用msgctl()函数删除消息队列。
消息队列消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点。
作为早期unix通信机制之一的信号能够传送的信息量有限,后来虽然POSIX 1003.1b在信号的实时性方面作了拓广,使得信号在传递信息量方面有了相当程度的改进,但是信号这种通信方式更像"即时"的通信方式,它要求接受信号的进程在某个时间范围内对信号做出反应,因此该信号最多在接受信号进程的生命周期内才有意义,信号所传递的信息是接近于随进程持续的概念(process-persistent),见附录1;管道及有名管道及有名管道则是典型的随进程持续IPC,并且,只能传送无格式的字节流无疑会给应用程序开发带来不便,另外,它的缓冲区大小也受到限制。
消息队列就是一个消息的链表。
可以把消息看作一个记录,具有特定的格式以及特定的优先级。
对消息队列有写权限的进程可以向中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。
消息队列是随内核持续的(参见附录1)。
目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。
考虑到程序的可移植性,新开发的应用程序应尽量使用POSIX消息队列。
在本系列专题的序(深刻理解Linux进程间通信(IPC))中,提到对于消息队列、信号灯、以及共享内存区来说,有两个实现版本:POSIX的以及系统V的。
Linux内核(内核2.4.18)支持POSIX信号灯、POSIX共享内存区以及POSIX消息队列,但对于主流Linux发行版本之一redhad8.0(内核2.4.18),还没有提供对POSIX进程间通信API的支持,不过应该只是时间上的事。
因此,本文将主要介绍系统V消息队列及其相应API。
在没有声明的情况下,以下讨论中指的都是系统V消息队列。
一、消息队列基本概念1.系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。
消息队列内核结构和msgget、msgctl函数⼀、消息队列1、消息队列提供了⼀个从⼀个进程向另外⼀个进程发送⼀块数据的⽅法2、每个数据块都被认为是有⼀个类型,接收者进程接收的数据块可以有不同的类型值3、消息队列与管道不同的是,消息队列是基于消息的,⽽管道是基于字节流的,且消息队列的读取不⼀定是先⼊先出。
4、消息队列也有管道⼀样的不⾜,就是每个消息的最⼤长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有⼀个上限(MSGMNI),这三个参数都可以查看:simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ cat /proc/sys/kernel/msgmax8192simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ cat /proc/sys/kernel/msgmnb16384simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ cat /proc/sys/kernel/msgmni1711⼆、IPC对象数据结构内核为每个IPC对象维护⼀个数据结构struct ipc_perm {key_t __key; /* Key supplied to xxxget(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 */};消息队列,共享内存和信号量都有这样⼀个共同的数据结构。
实验四进程间的高级通信1.消息的创建、发送和接收任务:使用系统调用msgget(),msgsnd(),msgrev()及msgctl()编制一长度为1k的消息发送和接受程序。
思路:(1)为了便于操作和观察结果,用一个程序作为引子,先后fork()两个子进程,server和client,进行通信。
(2)Server端建立一个key为75的消息队列,等待其他进程发送来的消息。
当遇到类型为1的消息,则作为结束信号,取消该队列,并退出server。
Server每接收到一个消息后显示一句“(server)received”。
(3)Client端使用key为75的消息队列,先后发送类型从10到1的消息,然后退出。
最后的一个消息,即是server端需要的结束信号。
Client每发送一条消息后显示一句“(client)sent”。
参考程序:#include<stdio.h>#include<sys/types.h>#include<sys/msg.h>#include<sys/ipc.h>#define MSGKEY 75struct msgform{long mtype;char mtrex[1030];}msg;int msgqid,i;void CLIENT(){int i;msgqid=msgget(MSGKEY,0777);for(i=10;i>=1;i--){msg.mtype=i;printf(“(client)sent\n”);msgsnd(msgqid,&msg,1024,0);}exit(0);}void SERVER(){msgqid=msgget(MSGKEY,0777|IPC_CREAT);do{msgrcv(msgqid,&msg,1030,0,0);printf(“(server)received\n”);}while(msg.mtype!=1);msgctl(msgqid,IPC_RMID,0);exit(0);}main(){while((i=fork())==-1);if(!i)SERVER();while((i=fork())==-1);if(!1) CLIENT();wait(0);wait(0);}从理论上说,应当是每当client发送一条消息后,server接收该消息,client再发送下一条,也即是应该交替出现“(client)sent”和“(server)received”,但实际结果大多不是这样,会出现几个“(client)sent”连续后再几个“(server)received”,请分析原因。
计算机操作系统(第四版)汤小丹课后答案完整版答:(1)发送者A 可用自己的私用密钥Kda对明文P进行加密,得到密文DKda(P)。
(2)A 再用B的公钥Keb对DKda (P)加密,得到EKeb(DKda(P))后送B。
(3)B收到后,先用私钥Kdb解密,得到DKda(EKeb(DKda(P)))=DKda (P)。
(4)B再用A的公钥Kea 对DKda(P)解密,得到EKeb(DKda(P))=P。
10.数字证明书的作用是什么?用一例来说明数字证明书的申请、发放和使用过程。
答:数字证明书又称公钥证明书,用于证明通信请求者的身份。
数字证明书的申请、发放和使用过程如下:(1) 用户A 先向CA申请数字证明书,A 应提供身份证明和希望使用的公钥A。
(2) CA 收到A 发来的申请报告后,若接受申请,便发给A 一份数字证明书,其中包括公钥A 和CA 发证者的签名等信息,并对所有信息利用CA 私钥加密(即对CA 进行数字签名)。
(3) 用户 A 在向B 发送信息时,由A用私钥对报文加密(数字签名),连同证明书发给B。
(4) 为能对收到的数字证明书解密,用户B须向CA 申请获得CA 的公钥B。
CA 收到用户 B 的申请后,可决定将公钥B发给用户B。
(5) 用户B 利用CA 公钥B 对数字证明书解密,确认该数字证明书系原件,并从数字证明书中获得公钥A,并且确认该公钥A系用户A的密钥。
(6) 用户B再利用公钥A 对用户A 发来的加密报文解密,得到用发来报文的真实明文。
11.何谓链路加密?其主要特点是什么?答:链路加密是对网络相邻节点间的通信线路上传输的数据的加密过程。
特点是:(1)相邻节点间的物理信道上传输的报文是密文,在所有中间节点上的报文则是明文。
(2)对不同的链路分别采用不同的加密密钥。
12.何谓端-端加密?其主要特点是什么?答:端-端加密是在源主机或前端机FEP高层(从传输层到应用层)对传输数据进行的加密。
Linux进程间通信(七):消息队列msgget()、msgsend()、msgrcv()。
下⾯来说说如何⽤不⽤消息队列来进⾏进程间的通信,消息队列与命名管道有很多相似之处。
有关命名管道的更多内容可以参阅我的另⼀篇⽂章:⼀、什么是消息队列消息队列提供了⼀种从⼀个进程向另⼀个进程发送⼀个数据块的⽅法。
每个数据块都被认为含有⼀个类型,接收进程可以独⽴地接收含有不同类型的数据结构。
我们可以通过发送消息来避免命名管道的同步和阻塞问题。
但是消息队列与命名管道⼀样,每个数据块都有⼀个最⼤长度的限制。
Linux⽤宏MSGMAX和MSGMNB来限制⼀条消息的最⼤长度和⼀个队列的最⼤长度。
⼆、在Linux中使⽤消息队列Linux提供了⼀系列消息队列的函数接⼝来让我们⽅便地使⽤它来实现进程间的通信。
它的⽤法与其他两个System V PIC机制,即信号量和共享内存相似。
1、msgget()函数该函数⽤来创建和访问⼀个消息队列。
它的原型为:int msgget(key_t, key, int msgflg);与其他的IPC机制⼀样,程序必须提供⼀个键来命名某个特定的消息队列。
msgflg是⼀个权限标志,表⽰消息队列的访问权限,它与⽂件的访问权限⼀样。
msgflg可以与IPC_CREAT做或操作,表⽰当key所命名的消息队列不存在时创建⼀个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,⽽只返回⼀个标识符。
它返回⼀个以key命名的消息队列的标识符(⾮零整数),失败时返回-1.2、msgsnd()函数该函数⽤来把消息添加到消息队列中。
它的原型为:int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);msgid是由msgget函数返回的消息队列标识符。
msg_ptr是⼀个指向准备发送消息的指针,但是消息的数据结构却有⼀定的要求,指针msg_ptr所指向的消息结构⼀定要是以⼀个长整型成员变量开始的结构体,接收函数将⽤这个成员来确定消息的类型。
消息队列程序c语言全文共四篇示例,供读者参考第一篇示例:消息队列是一种用于进程间通信的高效、灵活的通信机制。
在操作系统中,进程之间需要进行数据的传递和共享,而消息队列则提供了一种可靠的方式来实现进程间通信。
在C语言程序中,消息队列通常通过系统调用来进行操作。
本文将介绍消息队列的概念、实现原理以及在C语言程序中的应用。
### 消息队列的概念消息队列是一种用于进程间通信的通道,其中消息被存储在队列中,并由进程进行读取和写入。
消息队列中的消息可以是任意格式的数据,例如文本、音频、视频等。
消息队列通常具有先进先出(FIFO)的特性,即先发送的消息会先被接收。
消息队列可以分为两种类型:消息队列和消息队列。
在消息队列中,消息的接收方必须按照先进先出的顺序接收消息;而在消息队列中,消息的接收方可以按照自己的需求选择接收哪些消息。
消息队列的实现通常基于操作系统提供的相关功能。
在Unix/Linux系统中,消息队列可以通过系统调用`msgget`、`msgsnd`和`msgrcv`来实现。
- `msgget`用于创建或打开一个消息队列,返回一个消息队列标识符。
- `msgsnd`用于向消息队列中发送消息。
- `msgrcv`用于从消息队列中接收消息。
消息队列采用缓冲区的方式存储消息,不同进程可以通过消息队列进行数据交换。
消息队列的实现通常分为两个步骤:创建消息队列和使用消息队列进行进程间通信。
在C语言程序中,可以使用系统调用来创建和操作消息队列。
下面以一个简单的示例来说明消息队列在C语言程序中的应用:```c#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>// 定义消息结构体struct msgbuf {long mtype;char mtext[100];};// 创建消息队列key = ftok("msgq", 'A');msgid = msgget(key, IPC_CREAT | 0666);// 发送消息buf.mtype = 1;sprintf(buf.mtext, "Hello, message queue!");msgsnd(msgid, &buf, sizeof(buf.mtext), 0);// 删除消息队列msgctl(msgid, IPC_RMID, NULL);return 0;}```上面的示例演示了如何在C语言程序中创建、发送和接收消息队列。
消息队列及常见消息队列介绍⼀、消息队列(MQ)概述消息队列(Message Queue),是分布式系统中重要的组件,其通⽤的使⽤场景可以简单地描述为:当不需要⽴即获得结果,但是并发量⼜需要进⾏控制的时候,差不多就是需要使⽤消息队列的时候。
消息队列主要解决了应⽤耦合、异步处理、流量削锋等问题。
当前使⽤较多的消息队列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,⽽部分数据库如Redis、Mysql以及phxsql也可实现消息队列的功能。
⼆、消息队列使⽤场景消息队列在实际应⽤中包括如下四个场景:应⽤耦合:多应⽤间通过消息队列对同⼀消息进⾏处理,避免调⽤接⼝失败导致整个过程失败;异步处理:多应⽤对消息队列中同⼀消息进⾏处理,应⽤间并发处理消息,相⽐串⾏处理,减少处理时间;限流削峰:⼴泛应⽤于秒杀或抢购活动中,避免流量过⼤导致应⽤系统挂掉的情况;消息驱动的系统:系统分为消息队列、消息⽣产者、消息消费者,⽣产者负责产⽣消息,消费者(可能有多个)负责对消息进⾏处理;下⾯详细介绍上述四个场景以及消息队列如何在上述四个场景中使⽤:2.1 异步处理具体场景:⽤户为了使⽤某个应⽤,进⾏注册,系统需要发送注册邮件并验证短信。
对这两个操作的处理⽅式有两种:串⾏及并⾏。
(1)串⾏⽅式:新注册信息⽣成后,先发送注册邮件,再发送验证短信;在这种⽅式下,需要最终发送验证短信后再返回给客户端。
(2)并⾏处理:新注册信息写⼊后,由发短信和发邮件并⾏处理;在这种⽅式下,发短信和发邮件需处理完成后再返回给客户端。
假设以上三个⼦系统处理的时间均为50ms,且不考虑⽹络延迟,则总的处理时间:串⾏:50+50+50=150ms并⾏:50+50 = 100ms若使⽤消息队列:并在写⼊消息队列后⽴即返回成功给客户端,则总的响应时间依赖于写⼊消息队列的时间,⽽写⼊消息队列的时间本⾝是可以很快的,基本可以忽略不计,因此总的处理时间相⽐串⾏提⾼了2倍,相⽐并⾏提⾼了⼀倍;2.2 应⽤耦合具体场景:⽤户使⽤QQ相册上传⼀张图⽚,⼈脸识别系统会对该图⽚进⾏⼈脸识别,⼀般的做法是,服务器接收到图⽚后,图⽚上传系统⽴即调⽤⼈脸识别系统,调⽤完成后再返回成功,如下图所⽰:该⽅法有如下缺点:⼈脸识别系统被调失败,导致图⽚上传失败;延迟⾼,需要⼈脸识别系统处理完成后,再返回给客户端,即使⽤户并不需要⽴即知道结果;图⽚上传系统与⼈脸识别系统之间互相调⽤,需要做耦合;若使⽤消息队列:客户端上传图⽚后,图⽚上传系统将图⽚信息如uin、批次写⼊消息队列,直接返回成功;⽽⼈脸识别系统则定时从消息队列中取数据,完成对新增图⽚的识别。
消息队列程序 c语言
消息队列是一种在程序之间进行通信和数据交换的机制。
在C 语言中,可以通过系统提供的消息队列相关函数来实现消息队列的操作。
消息队列通常用于进程间通信,允许不同的进程在没有共享内存的情况下进行数据交换。
在C语言中,可以使用系统提供的消息队列函数来创建、发送和接收消息。
常用的函数包括:
1. `msgget`,用于创建一个新的消息队列或获取一个已存在的消息队列的标识符。
2. `msgsnd`,用于向消息队列发送消息。
3. `msgrcv`,用于从消息队列接收消息。
4. `msgctl`,用于控制消息队列,如删除消息队列等操作。
在使用消息队列时,需要注意消息的格式和大小,以及消息队列的权限和标识符等信息。
此外,还需要处理消息队列可能出现的
阻塞和超时等情况,确保程序的稳定性和可靠性。
除了基本的消息队列操作外,还可以结合多线程或者多进程的编程技术,实现更复杂的消息队列应用,比如实现生产者-消费者模型、事件驱动模型等。
总之,在C语言中使用消息队列需要充分了解消息队列的原理和相关函数的用法,同时结合具体的应用场景进行设计和开发,以实现程序之间的高效通信和数据交换。
《操作系统》课程教学大纲一、课程基本信息课程名称:操作系统先修课程:《计算机导论》(或《计算机应用基础》)、《C语言程序设计》、《数据结构》、《计算机组成原理》适用专业:计算机科学与技术、软件工程、网络工程等计算机及相关专业。
课程类别:专业教育必修课程/基础课程课程总学时:56-72 (其中理论40-56学时,实验16学时)二、课程目标通过本课程的学习,使学生具备下列能力:1.能够准确理解及掌握操作系统的基本概念、基本功能和基本原理,理解操作系统的整体运行过程。
2.能够理解及掌握操作系统的各组成部分,包括进程管理、调度、内存管理、文件管理、设备管理的功能及策略、算法、机制及相互关系。
3.能够运用操作系统原理、方法与技术分析问题和解决问题,并能利用C 语言描述相关算法。
4.在理解及掌握操作系统原理及算法的基础上,在进行硬件配置、软件设计及编程过程中,能够在资源和效率方面综合考虑,完善提高设计方案,提高利用操作系统知识解决实际问题的能力。
三、教学内容、要求及重难点第一章操作系统引论(3学时)教学要求:1.掌握操作系统的概念及功能,掌握操作系统的分类;2.掌握操作系统在计算机系统中的地位和作用;理解操作系统的大致运行过程;3.理解操作系统的特征;了解各种类型操作系统的特点及服务适应情况;4.了解操作系统的结构特征及发展概况,发展趋势。
教学重点:操作系统的概念、作用;操作系统的分类;操作系统的特征;操作系统的功能;操作系统的结构设计。
教学难点:操作系统的特征;操作系统的功能。
[实验名称]Linux系统管理及命令的使用[实验类型]验证型[实验要求]1.熟练Linux系统常用命令的使用;2.掌握Vi编辑器的使用方法;3.练习Linux shell的作用和主要分类,能编写简单的shell程序[实验学时]2学时第二章进程管理(10学时)教学要求:1.掌握进程的概念与特征;2.掌握进程的结构及进程控制的方法;3.掌握进程的同步与互斥,以及实现进程同步问题的硬件方法和软件方法;4.能用信号量机制解决进程的同步问题;5.掌握线程的基本概念;6.基本掌握利用管程解决同步问题的方法。
msgsnd、msgrcv、msgget函数是Linux系统中用于进程间通信的三个重要函数,它们可以实现进程之间的消息传递。
这些函数通常用于父子进程、无关联的进程或不同计算机上的进程之间进行通信。
下面将从简单到复杂地介绍这三个函数,以便更深入地理解它们的作用和用法。
1. msgsnd函数msgsnd函数是用于向消息队列中发送消息的函数。
消息队列是一种通信机制,它允许一个或多个进程向队列中添加消息,以便其他进程可以从队列中获取这些消息。
msgsnd函数的使用方法非常简单,通过指定消息队列的标识符、消息指针和消息长度,就可以向消息队列中发送消息。
在实际使用中,可以通过msgsnd函数将需要传递的消息发送到消息队列中,以便其他进程可以进行接收。
2. msgrcv函数msgrcv函数则是用于从消息队列中接收消息的函数。
当一个进程需要获取消息队列中的消息时,可以使用msgrcv函数来实现。
通过指定消息队列的标识符、消息类型、消息缓冲区和消息长度等参数,msgrcv函数可以从消息队列中接收指定类型的消息,并将消息存储到指定的消息缓冲区中。
这样,进程就可以获取其他进程发送的消息,并进行相应的处理。
3. msgget函数msgget函数用于创建一个新的消息队列或获取已经存在的消息队列的标识符。
通过msgget函数,进程可以获取对消息队列的访问权限,并进行消息发送和接收操作。
msgget函数可以指定消息队列的键值和访问权限等参数,以便获取一个合适的消息队列标识符。
这样,在进程间通信的过程中,就可以通过消息队列的标识符来确定消息队列的位置和属性,从而实现消息的发送和接收。
总结回顾:通过上述对msgsnd、msgrcv和msgget函数的介绍,我们可以清晰地了解到这三个函数在进程间通信中的重要作用。
通过消息队列这一通信机制,进程可以方便地进行消息的发送和接收,从而实现进程间的有效通信。
在实际应用中,这些函数可以帮助我们实现复杂的进程间通信,为进程间的协作和数据交换提供了便利的手段。
系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。
通常情况下,该id值通过ftok函数得到。
ftok原型如下:key_t ftok( char * fname, int id )fname就时你指定的文件名,id是子序号。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是:ls -i当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。
如果要确保key_t值不变,要目确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t值,比如:#define IPCKEY 0x111char path[256];sprintf( path, \"%s/etc/config.ini\", (char*)getenv(\"HOME\") );msgid=ftok( path, IPCKEY );[/code]同一段程序,用于保证两个不同用户下的两组相同程序获得互不干扰的IPC键值。
由于etc/config.ini(假定)为应用系统的关键配置文件,因此不存在被轻易删除的问题——即使被删,也会很快被发现并重建(此时应用系统也将被重起)。
ftok()的设计目的也在于此。
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int msgflg); //创建消息队列参数:key:消息队列关联的键。
msgflg:消息队列的建立标志和存取权限。
MSG结构体范文1. msg_type:用于区分消息的类型。
不同的类型对应不同的操作或功能。
例如,可以使用不同的消息类型来表示读取、写入、关闭文件等操作。
2. msg_data:用于存储消息的数据部分。
该字段的具体内容取决于消息的类型和应用场景。
例如,在文件操作中,msg_data可以存储要读取或写入的文件内容。
3. msg_len:用于记录消息的长度或大小。
这个字段对于接收方来说很重要,因为它可以帮助接收方分配足够的内存来存储消息数据。
5. msg_receiver:表示接收消息的组件或进程的标识符。
这个字段用于指定消息的目标接收者。
通过利用这些字段,可以建立具有丰富功能和灵活性的MSG结构体。
下面是一个使用MSG结构体的示例:```ctypedef structint msg_type;char msg_data[256];int msg_len;int msg_sender;int msg_receiver;}MSG;```在这个示例中,MSG结构体包含了一个整数字段msg_type来表示消息类型,一个字符数组字段msg_data来存储消息内容,一个整数字段msg_len来记录消息长度,以及两个整数字段msg_sender和msg_receiver来标识消息的发送者和接收者。
使用MSG结构体,可以在不同的组件或进程之间传递消息,并根据消息的类型和内容执行不同的操作。
例如,可以通过给msg_type赋不同的值来表示不同的消息类型,然后在接收端根据msg_type的值来执行对应的操作。
MSG结构体提供了一种简单而有效的方式来在计算机程序中传递消息。
它可以用于实现进程间通信(IPC)或网络通信等应用场景,使不同的组件能够相互交流和协调工作。
通过适当设计MSG结构体的字段,可以方便地处理各种类型的消息,以满足不同应用的需求。
msgsnd()为阻塞函数,当消息队列容量满或消息个数满会阻塞。
消息队列已被删除,则返回EIDRM错误;被信号中断返回E_INTR错误。
如果设置IPC_NOWAIT消息队列满或个数满时会返回-1,并且置EAGAIN错误。
msgrcv()解除阻塞的条件有以下三个:①消息队列中有了满足条件的消息。
②msqid代表的消息队列被删除。
③调用msgrcv()的进程被信号中断。
消息队列使用程序范例5. 消息队列控制范例msgctl.c源代码如下:#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/ipc.h>#include <sys/msg.h>#include <error.h>#define TEXT_SIZE 512struct msgbuf{long mtype ;char mtext[TEXT_SIZE] ;} ;int main(int argc, char **argv){int msqid ;struct msqid_ds info ;struct msgbuf buf ;struct msgbuf buf1 ;int flag ;int sendlength, recvlength ;msqid = msgget( IPC_PRIVATE, 0666 ) ;if ( msqid < 0 ){perror("get ipc_id error") ;return -1 ;}buf.mtype = 1 ;strcpy(buf.mtext, "happy new year!") ; sendlength = sizeof(struct msgbuf) - sizeof(long) ; flag = msgsnd( msqid, &buf, sendlength , 0 ) ;if ( flag < 0 ){perror("send message error") ;return -1 ;}buf.mtype = 3 ;strcpy(buf.mtext, "good bye!") ;sendlength = sizeof(struct msgbuf) - sizeof(long) ; flag = msgsnd( msqid, &buf, sendlength , 0 ) ;if ( flag < 0 ){perror("send message error") ;return -1 ;}flag = msgctl( msqid, IPC_STAT, &info ) ;if ( flag < 0 ){perror("get message status error") ;return -1 ;}printf("uid:%d, gid = %d, cuid = %d, cgid= %d\n" ,info.msg_perm.uid, info.msg_perm.gid, info.msg_perm.cuid, info.msg_perm.cgid ) ;printf("read-write:%03o, cbytes = %lu, qnum = %lu,qbytes= %lu\n" ,info.msg_perm.mode&0777, info.msg_cbytes, info.msg_qnum, info.msg_qbytes ) ;system("ipcs -q") ;recvlength = sizeof(struct msgbuf) - sizeof(long) ;memset(&buf1, 0x00, sizeof(struct msgbuf)) ;flag = msgrcv( msqid, &buf1, recvlength ,3,0 ) ;if ( flag < 0 ){perror("recv message error") ;return -1 ;}printf("type=%d, message=%s\n", buf1.mtype, buf1.mtext) ;flag = msgctl( msqid, IPC_RMID,NULL) ;if ( flag < 0 ){perror("rm message queue error") ;return -1 ;}system("ipcs -q") ;return 0 ;}编译gcc msgctl.c –o msgctl。
C++中消息队列函数实例详解C++ 中消息队列函数实例详解1.消息队列结构体的定义typedef struct{uid_t uid; /* owner`s user id */gid_t gid; /* owner`s group id */udi_t cuid; /* creator`s user id */gid_t cgid; /* creator`s group id */mode_t mode; /* read-write permissions 0400 MSG_R 0200 MSG_W*/ulong_t seq; /* slot usage sequence number*/}ipc_perm;typedef stuct{struct ipc_perm msg_perm; /* read_write perms */struct msg *msg_first; /* ptr to first message on queue */struct msg *msg_last; /* ptr to last message on queue */msglen_t msg_cbytes; /* used bytes current on queue */msgqnum_t msg_qnum; /* current num of message on queue */msglen_t msg_qbytes; /* max # of bytes allowed on queue */pid_t msg_lspid; /* pid of last msgsnd() */pid_t msg_lrpid; /* pid of last msgrcv() */time_t msg_stime; /* time of last msgsnd() */time_t msg_rtime; /* time of last msgrcv() */time_t msg_ctime; /* time of last msgctl() */}msqid_ds;typedef struct{long mtype;char mbuf[MSGLEN];}Message;2.创建消息队列:/***************************************************Function:int msgget(ket_t key,int oflag);Explain:create or view a message queueReturn :a int indetifyInclude:sys/msg.hintroduction:oflag: 0400 msg_r0200 msg_w0600 msg_wripc_creat: NO exist and then creat a queueexist : reference a queueipc_creat|ipc_excl: NO exist and then creat a queueexist : return error****************************************************/#include<stdio.h>#include<sys/msg.h>#include<stdlib.h>int MsgGet(int key){int ret;ret=msgget(key,0600|IPC_CREAT);// ret=msgget(key,0600|IPC_CREAT|IPC_EXCL);if(ret<0)perror("creat msgid error");printf("msgid=%d/n",ret);system("ipcs -q -i ret");return ret;}int main(int argc,char *agrv[]){printf("pleasse input msgkey:");scanf("%d",&key);MsgGet(key);return 0;}3.向消息队列中发送消息msgsnd/***********************************************************************************Function:int msgsnd(int msqid,const void *ptr,size_t length,int flag)Explain:send a message to a queueReturn:len: send message len;Include:sys/msg.hIntroduction:flag: 0 : if queue full wait:1>具备存放新消息的空间2>由msqid标识的消息队列从系统中删除(返回EIDRM错误)3>调⽤线程被某个捕获的信号所中断(返回EINTR错误)IPC_NOWAIT:如果没有存放新消息的空间,函数马上返回1>指定的队列中有太多的字节2>在系统范围存在太多的消息*****************************************************************************************/#include "typemsg.h"int MsgSnd(int msqid,char *buf,int len,int flag){int ret;ret=msgsnd(msqid,buf,len,flag);if(ret<0)perror("msgsnd error");system("ipcs -q");return ret;}int main(){int msqid,len,stype;Message msgb;memset(&msgb,0,sizeof(Message));printf("msgsnd:please input msqid:");scanf("%d",&msqid);printf("please input msgtype:");scanf("%d",&stype);msgb.mtype=stype;strcpy(msgb.mbuf,"zhangweia");MsgSnd(msqid,(char *)&msgb,sizeof(Message),0);return 0;}4.从队列中获取消息 msgrcv/*********************************************************************Function:int msgrcv(int msqid,const void *ptr,size_t msglen,long type,int flag)Explain:recv message order by typemsgrcv error: Argument list too long --> msglen的长度⼩于消息体中消息的长度Para :ptr: point to message structmsglen: 由ptr指向的缓冲区中数据部分的⼤⼩,这个是该函数能够返回的最⼤数据量type: message type;1> 0:返回队列中最早的消息2> ⼤于0:返回消息队列中类型为type的第⼀个消息3> ⼩于0:返回消息队列中类型⼩于或者等于type的绝对值的消息类型中最⼩的第⼀个消息flag: 0<wait> 没有消息或者消息类型不符合的时候,线程等待响应: 1>有⼀个所请求类型的消息可以获取2>msqid的消息队列被系统删除,返回⼀个EIDRM3>调⽤线程被某个捕获的信号所中断IPC_NOWAIT:在没有数据的情况下,⽴即返回⼀个ENOMSG错误MSGNOERROR:当所接受的消息数据部分⼤于msglen长度时,获取截短的数据部分,否则返回E2BIG错误message len*********************************************************************/#include "typemsg.h"int MsgRcv(int msqid,char *buf,int msglen,long type,int flag){int ret;ret=msgrcv(msqid,buf,msglen,type,flag);if(ret<0)perror("msgrcv error");system("ipcs -q");return ret;}int main(){int msqid,len;long ttype;Message mbuf;printf("msgrcv:please input recv msqid:");scanf("%d",&msqid);MsgRcv(msqid,(char *)&mbuf,8900,0,IPC_NOWAIT);printf("recv message=%s/n",mbuf.mbuf);Put_String((unsigned char *)&mbuf,sizeof(Message));return 0;}6.消息队列的控制msgctl/**********************************************************Function:int msgctl(int msqid,int cmd,struct msqid_ds *buff)Explain:cdm: IPC_RMID; delete msqidIPC_SET:IPC_STAT: return msqid stat*********************************************************/#include "typemsg.h"int MsgCtl(int msqid,int cmd,struct msqid_ds *buff){int ret;ret=msgctl(msqid,cmd,buff);if(ret<0){perror("msgctl error");return -1;}return 0;}int main(){int msqid,type;struct msqid_ds info;printf("please input msqid /nand type(1:icp_rmid;2:ipc_stat)");scanf("%d%d",&msqid,&type);if(type==1){MsgCtl(msqid,IPC_RMID,NULL);printf("delete queue success:%d/n",msqid);}else if(type==2){MsgCtl(msqid,IPC_STAT,&info);printf("get queue stat:%d/n",msqid);}return 0;}感谢阅读,希望能帮助到⼤家,谢谢⼤家对本站的⽀持!。
MSG一、实验目的1、了解什么是消息2、熟悉消息传送的机理。
二、实验内容消息的创建、发送和接收。
使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为1k的消息发送和接收的程序三、实验内容指导提示(一)、什么是消息消息(message)是一个格式化的可变长的信息单元。
消息机制允许由一个进程给其它任意的进程发送一个消息。
当一个进程收到多个消息时,可将它们排成一个消息队列。
消息使用二种重要的数据结构:一是消息首部,其中记录了一些与消息有关的信息,如消息数据的字节数;二个消息队列头表,其每一表项是作为一个消息队列的消息头,记录了消息队列的有关信息。
1、消息机制的数据结构(1)消息首部记录一些与消息有关的信息,如消息的类型、大小、指向消息数据区的指针、消息队列的链接指针等。
(2)消息队列头表其每一项作为一个消息队列的消息头,记录了消息队列的有关信息如指向消息队列中第一个消息和指向最后一个消息的指针、队列中消息的数目、队列中消息数据的总字节数、队列所允许消息数据的最大字节总数,还有最近一次执行发送操作的进程标识符和时间、最近一次执行接收操作的进程标识符和时间等。
2、消息队列的描述符UNIX中,每一个消息队列都有一个称为关键字(key)的名字,是由用户指定的;消息队列有一消息队列描述符,其作用与用户文件描述符一样,也是为了方便用户和系统对消息队列的访问。
(二)、涉及的系统调用1. msgget( )创建一个消息,获得一个消息的描述符。
核心将搜索消息队列头表,确定是否有指定名字的消息队列。
若无,核心将分配一新的消息队列头,并对它进行初始化,然后给用户返回一个消息队列描述符,否则它只是检查消息队列的许可权便返回。
系统调用格式:msgqid=msgget(key,flag)该函数使用头文件如下:#include<sys/types.h>#include<sys/ipc.h>#include<sys/msg.h>参数定义int msgget(key,flag)key_t key;int flag;其中:key是用户指定的消息队列的名字;flag是用户设置的标志和访问方式。
c语言消息队列的应用场景摘要:1.消息队列的概念和原理2.消息队列的应用场景3.消息队列的优缺点4.消息队列在C 语言中的实现5.总结正文:一、消息队列的概念和原理消息队列是一种进程间通信(IPC)的机制,它允许不同进程之间通过消息进行交互。
消息队列由内核负责管理,可以按顺序发送消息包(消息类型和消息内容),也可以全双工工作,即同时接收和发送消息。
消息队列可以不按消息的顺序接收消息,因此具有一定的灵活性。
二、消息队列的应用场景1.进程间通信:消息队列可以用于实现不同进程之间的通信,例如,一个进程需要向另一个进程发送数据或者通知,可以使用消息队列来实现。
2.异步处理:当一个进程需要异步处理某些任务时,可以使用消息队列来实现。
例如,一个进程需要等待某个事件发生,它可以通过消息队列发送一个消息,通知另一个进程该事件已经发生。
3.任务分发:在分布式系统中,消息队列可以用于任务分发。
例如,一个进程需要将某个任务分发给其他进程,它可以通过消息队列发送任务信息,其他进程收到消息后,可以按照任务要求进行处理。
4.日志记录:消息队列可以用于记录系统日志,当一个进程需要记录日志时,它可以将日志信息发送到消息队列,另一个进程可以实时接收并保存这些日志信息。
三、消息队列的优缺点1.优点:- 消息队列允许不同进程之间进行异步通信,提高了系统的并发性能。
- 消息队列具有一定的可靠性,即使接收进程没有及时处理消息,消息队列仍然可以保存消息。
- 消息队列可以实现进程间的解耦,降低了进程之间的依赖关系。
2.缺点:- 消息队列的通信效率较低,因为消息需要经过内核的复制和传输。
- 消息队列的实现较为复杂,需要涉及到进程间通信、内存管理等方面的知识。
四、消息队列在C 语言中的实现在C 语言中,可以使用sys/msg.h 库中的msgget、msgsnd 等函数来实现消息队列。
例如,可以通过msgget 函数创建一个消息队列,然后使用msgsnd 函数向消息队列发送消息。
Windows消息队列是一个用于进程间通信(IPC)的数据结构,它允许不同的进程通过发送和接收消息来进行通信。
在C语言中,可以使用Win32 API来创建和使用消息队列。
以下是一个简单的示例,展示了如何在C语言中使用Windows消息队列:c#include <windows.h>#include <stdio.h>// 定义消息队列名称#define QUEUE_NAME "MyMessageQueue"// 发送消息的函数void sendMessage(char* message) {HANDLE hQueue;// 打开或创建一个消息队列if (!(hQueue = CreateEvent(NULL, FALSE, FALSE, QUEUE_NAME))) {printf("Failed to create event\n");return;}// 将消息发送到队列中if (!PostEvent(hQueue, message)) {printf("Failed to post message\n");return;}// 关闭事件句柄CloseHandle(hQueue);}// 接收消息的函数char* receiveMessage() {HANDLE hQueue;// 打开或创建一个消息队列if (!(hQueue = CreateEvent(NULL, FALSE, FALSE, QUEUE_NAME))) {printf("Failed to create event\n");return NULL;}// 从队列中接收消息char* message = (char*)WaitForSingleObject(hQueue, INFINITE);// 关闭事件句柄CloseHandle(hQueue);return message;}int main() {char* message = receiveMessage();if (message) {printf("Received message: %s\n", message);// 释放消息内存LocalFree(message);} else {printf("Failed to receive message\n");}return 0;}这个示例代码演示了如何使用Windows消息队列来发送和接收消息。
消息队列是一种进程间通信或线程间通信的方式,它允许进程或线程发送和接收消息。
在C语言中,我们可以使用POSIX消息队列API来实现消息队列。
以下是一个简单的例子:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <sys/stat.h>#include <mqueue.h>#define QUEUE_NAME "/test_queue"#define MAX_SIZE 1024#define MSG_STOP "exit"// 发送者void send() {mqd_t mq;char buffer[MAX_SIZE + 1];int must_stop = 0;// 打开队列mq = mq_open(QUEUE_NAME, O_WRONLY);printf("发送者开始发送消息\n");while (!must_stop) {printf("输入你的消息:");fgets(buffer, MAX_SIZE, stdin);buffer[strlen(buffer)-1] = '\0'; // 删除换行符if (strcmp(buffer, MSG_STOP) == 0) {must_stop = 1;} else {mq_send(mq, buffer, MAX_SIZE, 0);printf("消息 '%s' 发送成功\n", buffer); }}// 关闭队列并删除它mq_close(mq);mq_unlink(QUEUE_NAME);}// 接收者void receive() {mqd_t mq;ssize_t bytes_read;struct mq_attr attr;char buffer[MAX_SIZE + 1];int must_stop = 0;// 打开队列,设置队列的属性,如果队列不存在则创建它attr.mq_flags = 0;attr.mq_maxmsg = 10; // 队列中最大的消息数attr.mq_msgsize = MAX_SIZE; // 每个消息的最大大小attr.mq_curmsgs = 0; // 当前队列中的消息数mq = mq_open(QUEUE_NAME, O_RDONLY | O_CREAT, S_IRWXU | S_IRWXG, &attr);printf("接收者开始接收消息\n");while (!must_stop) {bytes_read = mq_receive(mq, buffer, MAX_SIZE, NULL); // 接收消息,并把消息放入buffer中if (bytes_read >= 0) {buffer[bytes_read] = '\0'; // 在消息的末尾添加终止符,使其成为有效的C字符串printf("接收到消息: %s\n", buffer); // 打印消息if (strcmp(buffer, MSG_STOP) == 0) { // 如果接收到的是"exit",则退出循环must_stop = 1;} else { // 如果接收到的是其他消息,则把它放入队列中,以便其他进程可以收到它mq_send(mq, buffer, MAX_SIZE, 0); // 把消息放入队列中,等待其他进程来接收它(循环中的其他进程或循环外部的其他进程)}} else { // 如果接收消息时出错,则退出循环(例如,如果队列为空)perror("mq_receive"); // 打印错误信息(例如,如果队列为空)并退出循环(必须停止)must_stop = 1; // 设置标志以退出循环(必须停止)并退出程序(程序结束)。
消息队列函数由、、、四个函数组成.下面地表格列出了这四个函数地函数原型及其具体说明.
Ÿ 、、、、设置为.文档收集自网络,仅用于个人学习
Ÿ 设置为当前时间.
Ÿ 设成系统地限制值.
Ÿ 地读写权限写入中.
Ÿ 结构地和成员被设置成当前进程地有效用户,和成员被设置成当前进程地有效组.文档收集自网络,仅用于个人学习
()为阻塞函数,当消息队列容量满或消息个数满会阻塞.消息队列已被删除,则返回错误;被信号中断返回错误.文档收集自网络,仅用于个人学习
如果设置消息队列满或个数满时会返回,并且置错误.
()解除阻塞地条件有以下三个条件:
①不满足消息队列满或个数满两个条件,即消息队列中有容纳该消息地空间.
②代表地消息队列被删除.
③调用函数地进程被信号中断.
①消息队列中有了满足条件地消息.
②代表地消息队列被删除.
③调用()地进程被信号中断.
消息队列使用程序范例
. 消息队列控制范例
源代码如下:
<>
<>
<>
<>
<>
<>
{
;
[] ;
} ;
( , **)
{
;
;
;
;
;
, ;
( , ) ;
( < )
{
(" ") ;
;
}
;
(, " !") ;
( ) () ;文档收集自网络,仅用于个人学习
( , , , ) ;
( < )
{
(" ") ;
;
}
;
(, " !") ;
( ) () ;文档收集自网络,仅用于个人学习
( , , , ) ;
( < )
{
(" ") ;
;
}
( , , ) ;
( < )
{
(" ") ;
;
}
(", , , \" ,
, , , ) ;文档收集自网络,仅用于个人学习
(", , , \" ,文档收集自网络,仅用于个人学习
, , , ) ;文档收集自网络,仅用于个人学习
(" ") ;
( ) () ;文档收集自网络,仅用于个人学习
(, , ( )) ;
( , , ) ;
( < )
{
(" ") ;
;
}
(", \", , ) ;文档收集自网络,仅用于个人学习
( , ) ;
( < )
{
(" ") ;
;
}
(" ") ;
;
}
编译– .
执行,执行结果如下:
, , ,
, , , 文档收集自网络,仅用于个人学习
文档收集自网络,仅用于个人学习
文档收集自网络,仅用于个人学习, !
文档收集自网络,仅用于个人学习
. 两进程通过消息队列收发消息
()发送消息队列程序
源代码如下:
<>
<>
<>
<>
<>
<>
{
;
;
[] ;
[] ;
} ;
*()
{
;
* ;
[] ;
( ) ;
() ;
(,""> , >>);文档收集自网络,仅用于个人学习;
}
( , **)
{
;
;
;
;
;
, ;
;
("", ) ;
( < )
{
(" ") ;
;
}
( , ) ;
( < )
{
(" ") ;
;
}
;
;
(, ()) ;
(, " !") ;
( ) () ;文档收集自网络,仅用于个人学习
( , , , ) ;
( < )
{
(" ") ;
;
}
;
;
(, ()) ;
(, " !") ;
( ) () ;文档收集自网络,仅用于个人学习
( , , , ) ;
( < )
{
(" ") ;
;
}
(" ") ;
;
}
()接收消息队列程序
源代码如下:
<>
<>
<>
<>
<>
{
;
;
[] ;
[] ;
} ;
( , **)
{
;
;
;
;
;
;
;
("", ) ;
( < )
{
(" ") ;
;
}
( , ) ;
( < )
{
(" ") ;
;
}
( ) () ;文档收集自网络,仅用于个人学习(, , ( )) ;
;
( , , ) ;文档收集自网络,仅用于个人学习( < )
{
(" \") ;
;
}
(", \", , , ) ;文档收集自网络,仅用于个人学习(" ") ;
;
}
()编译与执行程序
①在当前目录下利用>建立空文件.
②编译发送消息队列程序.
③执行,执行结果如下:
文档收集自网络,仅用于个人学习
文档收集自网络,仅用于个人学习
④编译接收消息程序
⑤执行,执行结果如下:
, !
文档收集自网络,仅用于个人学习
文档收集自网络,仅用于个人学习
⑥利用删除该消息队列.因为消息队列是随内核持续存在地,在程序中若不利用函数或在命令行用命令显式地删除,该消息队列就一直存在于系统中.另外信号量和共享内存也是随内核持续存在地.文档收集自网络,仅用于个人学习
摘录自《深入浅出工具与编程》。