消息队列
目录
引入
-- 进程间通信 (IPC)是指在不同进程之间传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。
-- 这章讲消息队列
-
相当于系统级别的链表(系统开着,消息队列在。系统关,消息队列关)-- 所有进程都可使用
-
多个进程间进行数据传输 -- 消息队列
一、消息队列的特点
-- 类似于管道
-
(1)先进先出,数据读出来会从消息队列中消失。
-
(2)要进行消息的读取,必须有消息否则会读阻塞。
-
(3)消息队列满了,会产生写阻塞。
-
(4)有消息类型之分,用来确定读取的消息类型
-- 消息队列可以解决的问题:多个进程间进行数据的传输
二、使用指令查看消息队列
-- 指令:ipcs
- ipas可以查看系统下的system V的状态
-- 指令:ipcs -q 只查看消息队列
-- 消息队列的相关信息:
-
键值:获取消息队列 id 的唯一标识符,一个键值对应一个消息队列的 id,是八位的十六进制,例如 0x12345678
-
msqid:用于区分不同的消息队列 也代表该消息队列的号(id)
-
拥有者:谁创建的
-
权限:对该消息队列的操作权限
例:666 可读可写 -
已用字节数:消息队列中一共存放了多少个字节的信息
-
消息:存放了消息的个数
三、使用消息队列进行通信的步骤
1、获取键值
(1)函数获取:
-- 函数头文件
- #include <sys/types.h>
- #include <sys/ipc.h>
-- 函数原型
- key_t ftok(const char *pathname, int proj_id)
-- 函数的作用:
- 通过传入的参数来获取指定的键值(ftok的两个参数一样,获取的键值就一样)
-- 函数的参数:
- pathname:必须是存在的路径
- proj_id:0~255
-- 函数的返回值:
- 会根据函数的参数来返回一个键值
(2)自己定义:
- #define my_key 0x12345678
-- 键值的作用:
- 一样的键值可以让不同进程来获取到同一个消息队列的id号
- 一个键值对应一个id号,是一一对应的。具有唯一性。
2、创建或获取消息队列 id
-- 函数头文件
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
-- 函数原型
- int msgget(key_t key, int msgflg)
-- 函数的作用:
- 创建或获取消息队列的 id 用于进程间通信
-- 函数的参数:
- key:键值 相同的键值可以获取相同的消息队列 id
- msgflg:固定填写 IPC_CREAT|0666
-- 函数的返回值:
- 成功返回 消息队列的 id >= 0
- 失败返回 -1
3、使用消息队列进行数据的传输
-- 收发的数据类型必须为结构体
-- 函数的头文件
- #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:要将消息发送到哪一个消息队列中去
-
msgsz:填写 mtext 的大小 ,填写:第二个参数的结构体大小 - 8
-
msgflg:填0是阻塞发送,如果消息队列空间不够,会阻塞,直到有空间可以进行写入
-- IPC_NOWAIT 非阻塞发送 -
msgp:发送的消息的首地址
-- 这里必须要用结构体 需要自己在程序中定义(发送和接收的结构体必须定义的一模一样)
struct msgbuf {
long mtype;
/* message type, must be > 0 */
char mtext[1];
/* message data */
xxxx;
.....;
};
-- 结构体中的第一个成员必须为 long 类型,赋值时必须给大于 0 的值
-- 函数的返回值:
- 成功返回 0
- 失败返回 -1
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define key 0x12345678
struct student
{
long mtype; -- 第一个数据类型必须是long型
int id;
char name[20];
};
int main()
{
//key_t key = ftok("/home/pimouren/learn", 55);
printf("%x\n",key);
int id = msgget(key,IPC_CREAT|0666);
if(id == -1)
{
perror("msgget");
return -1;
}
printf("id = %d\n",id);
struct student stu;
printf("请输入学生的学号!\n");
scanf("%d",&stu.id);
printf("请输入学生的名字!\n");
scanf("%s",stu.name);
int mm = msgsnd(id, &stu,sizeof(stu)-8, 0);
if(mm == -1)
{
perror("msgsnd");
return -1;
}
return 0;
}
-- 再次向消息队列中写入数据,已用字节数发生改变
4、msgrcv -- 从消息队列中读取数据
-- 函数头文件
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
-- 函数的原型
- ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
-- 函数的作用:
- 从消息队列中进行数据的读取
-- 函数的参数:
- msqid:要从哪一个消息队列读取消息
- msgp:读取到的消息保存的首地址
- msgsz:要读取的消息字节数,填写结构体大小 - 8
- msgtyp:要接受的消息类型
"> 0"
-- 接收指定的消息类型中的第一条消息
"0"
-- 接收消息队列中的第一条消息
"<0"
-- 接收小于 msgtyp 绝对值的消息类型
例如 填写-3, |-3| == 3 ,那么可以读取 1 或2 的消息类型
- msgflg: 0 阻塞接收 如果没有 msgtyp 指定消息类型会一直阻塞 直到有该消息类型来到 IPC_NOWAIT 非阻塞
-- 函数的返回值:
- 成功返回 实际读取到的字节数
- 失败返回 -1
5、消息队列的多种操作函数
-- 函数头文件
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
-- 函数原型
- int msgctl(int msqid, int cmd, struct msqid_ds *buf);
-- 函数的作用:
- 对消息队列进行多种操作 例如:获取消息队列的信息, 更改消息队列设置, 删除消息队列
-- 函数的参数:
- msqid:消息队列的 id 你要对哪一个消息队列进行操作
- cmd:要进行的具体操作
IPC_STAT 获取消息队列的信息
IPC_SET 更改消息队列的设置
IPC_RMID 删除消息队列
当 cmd 为 IPC_RMID 时 第三个参数给 NULL buf:结构体指针 用于传出和设置消息队列属性
-- 函数的返回值:
- 成功 返回 0
- 失败 返回 -1
-- 这个函数主要用来删除消息队列
-- 使用指令删除消息队列
- 指令:ipcrm -q msgid