Linux消息队列总结
来源:互联网 发布:中英互译软件哪个好 编辑:程序博客网 时间:2024/05/17 22:43
本文章主体转自http://blog.csdn.net/stonecao/article/details/10364287
在其基础上添加了一些补充说明。
1.消息队列简介
实现linux进程通信的方式有5种:
--信号(Singal)
--管道(Pipe)
--消息队列(Message)
--信号量(Semaphore)
每种进程通信方式实现方式和功能不一样,带来适用的场景也有所不同,消息队列是链表队列,它通过内核提供一个struct msqid_ds *msgque[MSGMNI]向量维护内核的一个消息队列列表,因此linux系统支持的最大消息队列数由msgque数组大小来决定,每一个msqid_ds表示一个消息队列,并通过msqid_ds.msg_first、msg_last维护一个先进先出的msg链表队列,当发送一个消息到该消息队列时,把发送的消息构造成一个msg结构对象,并添加到msqid_ds.msg_first、msg_last维护的链表队列,同样,接收消息的时候也是从msg链表队列尾部查找到一个msg_type匹配的msg节点,从链表队列中删除该msg节点,并修改msqid_ds结构对象的数据。
2.消息队列的数据结构
--1.struct msqid_ds *msgque[MSGMNI]向量:
msgque[MSGMNI]是一个msqid_ds结构的指针数组,每个msqid_ds结构指针代表一个系统消息队列,msgque[MSGMNI]的大小为MSGMNI=128,也就是说系统最多有MSGMNI=128个消息队列
--2.struct msqid_ds
一个消息队列结构
struct msqid_ds 中主要数据成员介绍如下:
struct msqid_ds
{
struct ipc_perm msg_perm;
struct msg *msg_first; /*消息队列头指针*/
struct msg *msg_last; /*消息队列尾指针*/
__kernel_time_t msg_stime; /*最后一次插入消息队列消息的时间*/
__kernel_time_t msg_rtime; /*最后一次接收消息即删除队列中一个消息的时间*/
__kernel_time_t msg_ctime;
struct wait_queue *wwait; /*发送消息等待进程队列*/
struct wait_queue *rwait;
unsigned short msg_cbytes;
unsigned short msg_qnum; /*消息队列中的消息个数*/
unsigned short msg_qbytes;
__kernel_ipc_pid_t msg_lspid; /*最后一次消息发送进程的pid*/
__kernel_ipc_pid_t msg_lrpid; /*最后一次消息发送进程的pid*/
};
--3.struct msg 消息节点结构:
msqid_ds.msg_first,msg_last维护的链表队列中的一个链表节点
struct msg
{
msg *msg_next; /*下一个msg*/
long msg_type; /*消息类型*/
*msg_spot; /*消息体开始位置指针*/
msg_ts; /*消息体长度*/
message; /*消息体*/
}
--4.msgbuf消息内容结构:
msg 消息节点中的消息体,也是消息队列使用进程(消息队列发送接收进程)发送或者接收的消息
struct msgbuf
{
long mtype; --消息类型
char mtext[n]; --消息内容
}
PS:该消息体可以由用户自定义,但是必须遵守第一个结构体成员为 long类型,mtext消息内容长度至少为一个字节,的规则即可,且该类型变量值需 ">0";其下介绍的函数msgsnd,msgrcv中的参数 size_t msgsz,值需为结构体 struct msgbuf.mtext[n]中n的值。
3.消息队列的使用
PS:所需头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
--1.消息队列Key的获取:
在程序中若要使用消息队列,必须要能知道消息队列key,因为应用进程无法直接访问内核消息队列中的数据结构,因此需要一个消息队列的标识,让应用进程知道当前操作的是哪个消息队列,同时也要保证每个消息队列key值的唯一性
----a.通过ftok函数获取
key_t ftok(const char *pathname, int proj_id);
key_t key;
key=ftok(".","a")
该函数通过一个路径名称映射出一个消息队列key(我的理解是使用路径映射的方式比较容易获取一个唯一的消息队列key)
PS:用 pathname 和 proj_id 这两个参数来获取一个特定的键值"key";pathname为一路径名,注意该路径的读写权限,该权限应该会被
该消息队列继承,proj_id是一个需要进程间通信的两个进程约定好的一个值,用来配合路径名得到一个相同的键值“key”;
----b.直接定义key:
#define MSG_KEY 123456
自定义key的方式要注意避免消息队列的重复。
--2.获取或者打开一个消息队列
----a.使用说明
int msgget(key_t key, int msgflg);
qid=msgget(key_t key, int msgflag)
--key: 消息队列key
--msgflag:
IPC_PRIVATE:创建一个该进程独占的消息队列,其它进程不能访问该消息队列
IPC_CREAT:若消息队列不存在,创建一个新的消息队列,若消息队列存在,返回存在的消息队列
IPC_CREAT | IPC_EXCL: IPC_EXCL标志本身没有多大意义,与IPC_CREAT一起使用,保证只创建新的消息队列,若对应key的消息队列已经存在,则返回错误
IPC_NOWAIT:小队列以非阻塞的方式获取(若不能获取,立即返回错误)
----b.函数原因
------1)如果key==IPC_PRIVATE,则申请一块内存,创建一个新的消息队列(数据结构msqid_ds),将其初始化后加入到msgque向量表中的某个空位置处,返回标示符。
------2)在msgque向量表中找键值为key的消息队列,如果没有找到,结果有二:
msgflag表示不创建新的队列,则错误返回。
msgflag表示要创建新的队列(IPC_CREAT),则创建新消息队列,创建过程如1)。
-------3)如果在msgque向量表中找到了键值为key的消息队列,则有以下情况:
如果msgflg表示一定要创建新的消息队列而且不允许有相同键值的队列存在,则错误返回。
如果找到的队列是不能用的或已经损坏的队列,则错误返回。
认证和存取权限检查,如果该队列不允许msgflg要求的存取,则错误返回。
正常,返回队列的标识符。
--3.发送一个消息到消息对列
----a.使用说明:
int msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
------msqid为消息队列的qid
------msgp对应消息内容结构体指针
------msgsz消息的大小即msgp指针指向的消息结构体的大小
------msgflg消息标志
0:忽略该标志位,以阻塞的方式发送消息到消息队列
IPC_NOWAIT:以非阻塞的方式发送消息,若消息队列满,函数立即返回。
------返回:
0: 成功
-1:非阻塞方式访问满消息队列返回
EACCES:没有该消息队列写权限
EFAULT:消息队列地址无法获取
EIDRM:消息队列已经被删除
EINTR:消息队列等待写入的时候被中断
ENOMEM:内存不够
----b.函数原理:
1)计算id = (unsigned int) msqid % MSGMNI,然后根据id在linux系统消息队列向量msgque[MSGMNI]中查找对应的消息队列,并进行认证检查,合法性检查
2)如果队列已满,以可中断等待状态(TASK_INTERRUPTIBLE)将当前进程挂起在wwait等待队列(发送消息等待队列)上(msgflag==0)。
3)否则 根据msgbuf的大小申请一块空间,并在其上创建一个消息数据结构struct msg(内核空间),将消息缓冲区中的消息内容拷贝到该内存块中消息头的后面(从用户空间拷贝到内核空间)。
4)将消息数据结构加入到消息队列的队尾,修改队列msqid_ds的相应参数。
5)唤醒在该消息队列的rwait进程队列(读等待进程队列)上等待读的进程,并返回。
--4.从消息队列接收一个消息到msgbuf*
----a.使用说明
int msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,long msgtyp, int msgflg)
PS:linux下定义为 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
----msqid为消息队列的qid
----msgp是接收到的消息将要存放的缓冲区
----msgsz是消息的大小
----msgtyp是期望接收的消息类型
----msgflg是标志
0:表示忽略
IPC_NOWAIT:如果消息队列为空,不阻塞等待,返回一个ENOMSG
----返回
0:成功
-1:消息长度大于msgsz
EACCES:没有该消息队列读权限
EFAULT:消息队列地址无法获取
EIDRM:消息队列已经被删除
EINTR:消息队列等待写入的时候被中断
ENOMEM:内存不够
----b.函数原理:
1)计算id = (unsigned int) msqid % MSGMNI,然后根据id在msgque[MSGMNI]中查找对应的消息队列,并进行认证检查,合法性检查
2)根据msgtyp搜索消息队列,情况有二:
----如果找不到所要的消息,则以可中断等待状态(TASK_INTERRUPTIBLE)将当前进程挂起在rwait等待队列上
----如果找到所要的消息,则将消息从队列中摘下,调整队列msqid_ds参数,唤醒该消息队列的wwait进程队列上等待写的进程,将消息内容拷贝到用户空间的消息缓冲区msgp中,释放内核中该消息所占用的空间,返回
--5.消息的控制
----a.使用说明:
int msgctl (int msqid, int cmd, struct msqid_ds *buf)
------msqid:为消息队列的qid
------cmd:为该函数要对消息队列执行的操作
IPC_STAT:取出消息队列的msqid_ds结构体并将参数存入buf所指向的msqid_ds结构对象中
IPC_SET:设定消息队列的msqid_ds 数据中的msg_perm 成员。设定的值由buf 指向的msqid_ds
结构给出。
IPC_EMID:将队列从系统内核中删除。
----buf:消息队列msqid_ds结构体指针
----b.函数作用
对消息队列进行设置以及相关操作,具体操作由cmd指定。
- linux消息队列总结
- Linux消息队列总结
- linux消息队列总结
- Linux进程通信总结(四) --消息队列
- Android消息队列总结
- 消息队列mq总结
- 消息队列使用总结
- linux进程间通信-----System V消息队列总结实例
- Linux消息队列编程
- linux消息队列
- linux消息队列操作
- linux IPC-消息队列
- linux消息队列函数
- Linux消息队列操作
- linux 消息队列
- linux IPC-消息队列
- Linux的消息队列
- Linux消息队列
- 管理Activity生命周期
- 30 个使用 CSS3 制作网页按钮的教程 30 Examples of CSS3 Buttons Tutorials
- 绝对布局和相对布局
- 【问底】徐汉彬:Web系统大规模并发——电商秒杀与抢购
- [转]QT实现拖放文件
- Linux消息队列总结
- 《同桌的你》观后感
- javascript学习第一课--简介
- Android Gmail下拉刷新的横向进度条如何使用 ------- SwipeRefreshLayout
- JAVA高并发访问之解决方案
- POJ1125 Stockbroker Grapevine
- 插件 and 外挂
- android内存查看heap中 type 1-byte array (byte[],boolean[])就是bitmap所占内存
- 几种xml解析方法