Linux应用开发-进程间通信-消息队列

本文详细阐述了消息队列的特点,如随机查询、高效通信和数据格式化,同时也讨论了其缺点如消息体长度限制和数据拷贝问题。此外,文中介绍了与消息队列交互的关键API,如ftok()、msgget()、msgsnd()、msgrcv()和msgctl()的用法和功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

特点

  1. 消息队列允许一个或多个进程向它写入或读取消息。

  2. 消息队列可以实现消息的随机查询,不一定非要以先进先出的次序读取消息,也可以按消息的类型读取。比有名管道的先进先出原则更有优势。

  3. 对于消息队列来说,在某个进程往一个队列写入消息之前,并不需要另一个进程在该消息队列上等待消息的到达。而对于管道来说,除非读进程已存在,否则先有写进程进行写入操作是没有意义的。

  4. 消息队列的生命周期随内核,如果没有释放消息队列或者没有关闭操作系统,消息队列就会一直存在。而匿名管道随进程的创建而建立,随进程的结束而销毁。

管道的通信方式效率是低下的,不适合进程间频繁的交换数据。这个问题,消息队列的通信方式就可以解决。A进程往消息队列写入数据后就可以正常返回,B进程需要时再去读取就可以了,效率比较高。

数据会被分为一个一个的数据单元,称为消息体,消息发送方和接收方约定好消息体的数据类型,不像管道是无格式的字节流类型,这样的好处是可以边发送边接收,而不需要等待完整的数据。

缺点:

每个消息体有一个最大长度的限制,并且队列所包含消息体的总长度也是有上限。

消息队列通信过程中存在用户态和内核态之间的数据拷贝问题。

相关API

ftok()

该函数是根据pathname指定的文件或目录的索引节点号和proj_id计算并返回一个key_t类型的ID值,失败则返回-1;

key_t ftok(const char **pathname,int proj_id);

第一个参数pathname是一个系统中必须存在的文件或文件夹的路径,会使用该文件的索引节点;
第二个参数prij_id是用户指定的一个子序号,这个数字有的称之为project ID,它是一个8bit的整数,取值范围为1~255.
**注意:**如果要确保key值不变,要么确保fork()的文件不会被删除,要么不用fork()指定一个固定的key值。

msgget()

创建一个新队列或者打开一个现有队列,成功返回一个非负整数,即该共享内存段的标识码,失败返回-1;

#include<sys/msg.h>
int msgget(key_t key,int msgflg);

key是fork()返回的key_t类型键值;或者手动指定一个键值。

msgflg是创建标志:IPC_CREAT,不存在则创建,存在则返回已有的mqid,IPC_CREAT|IPC_EXCL,不存在则创建,存在则返回出错。

msgsnd()

将新消息添加到队列尾端,也就是发送一条消息,必须要有写消息队列的权限。成功返回0;失败返回-1;并设置errno.

#include<sys/msg.h>
int msgsnd(int msqid,const void *ptr,size_t msgsz,int magflg);

msgid 是由msgget函数返回的消息队列 ID;

ptr是一个指针,它指向要发送的消息结构体类型的变量,消息结构在两方面受到制约。首先,它必须小于系统规定的上限值;其次,它必须以一个long int 长整数开始,接收者函数将利用这个长整数确定消息的类型,其参考类型定义如下:

typedef struct s_msgbuf
{
    long    mtype;                /*positive message type */
    char    mtext[512];         /*message data,of  length nbytes */
}t_msgbuf;

msgsz是要发送消息的长度;

msgflg控制着当前消息队列已满或系统上限时将要发生的事情,设置为IPC_NOWAIT表示队列已满不等待,返回EAGAIN错误。

msgrcv()

用于从队列中取消息,成功返回实际放到接收缓冲区里去的个数,失败返回-1;并设置errno.

#include<sys/msg.h>
ssize_t msgrcv(int msqid,void *ptr,size_t msgsz,long msgtyp,int msgflg);

msgid是由msgget 函数返回的消息队列ID;

ptr是一个指针,它指向准备接收的消息;

msgsz是msgp指向的消息长度,这个长度不含保存消息类型的long int 长整型;

msgtype是消息的类型,它可以指定想要哪一种消息,可以实现接收优先级的简单形式;

type=0 返回队列中的第一个值;
type>0 返回队列中消息类型为type的第一个消息;
type<0 返回队列中消息类型值≤type绝对值的消息,如果这种消息有若干个,则取类型值最小的消息。

type 值非0 用于以非先进先出次序读取消息,程序若给消息赋予优先权,则type就可以是优先权值,如果一个消息队列由多个客户进程和一个服务器进程使用,则type字段可以用来包含客户进程的进程ID(前提是ID可以存放在长整型中)。

msgctl()

msgctl函数对队列执行多种操作,用于控制消息队列。它和进程间通信的另外两种方法(信号量和共享存储)中的函数(semctl和shmctl)都是类似于ioctl函数(也叫垃圾桶函数)

#include<sys/msg.h>
int msgctl(int msqid,int cmd,struct msqid_ds *buf);

msgid:msgget 函数返回的消息队列ID;

cmd:该参数指定对msqid指定的队列要执行的命令,可取一下三个值:

IPC_STAT:取msqid_ds结构,并将它存放在buf 指向的结构中;

IPC_SET:将字段msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_qbytes从buf指向的结构复制到与 这个队列相关的msqid_ds结构中;

IPC_RMID:从系统中删除该消息队列以及仍在该队列中的所有数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萌新程序猿~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值