Linux内核编程 消息队列使用案例

目录

一:IPC进程间通信

二:消息队列

三:消息队列的使用

四:进程间通信 消息队列编程

五:msgsnd函数 

六:消息队列的发送与接收


一:IPC进程间通信

现在linux使用的进程间通信方式:

1 管道(pipe)和命名管道(FIFO)

2 信号(signal)

3 消息队列【系统管理】

4 共享内存【系统管理】

5 信号量【系统管理】

6 套接字(socket)

socket套接字就是网络,网络编程也是IPC技术

利用网络实现两个应用程序之间的通信 【客户端和服务器】【两个进程间通信】

上面IPC技术中的 1-5都是本机操作,而6是两台计算机操作

二:消息队列

消息队列提供了一个 从一个进程向另外一个进程发送一块数据【一块数据 结构体】的方法

每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

消息队列也有管道一样的不足,就是每个数据块的最大长度是有上限的[结构体有一定大小],系统上全体队列的最大总长度也有一个上限[系统管理着消息队列]

内存三剑客:

消息队列 、 共享内存 、 信号量

Linux操作系统可以通过命令查看      ipcs

消息队列 共享内存 信号量都是由操作系统直接管理的

信号和管道是由代码编写的main函数的主进程来管理

由操作系统管理的,那么它的整个内存区域不算做是进程间的;

信号和管道 的 内存区域是在 进程中的

消息队列 共享内存和信号量的内存区域在操作系统中【也就是在当前的要通信的两个进程的外部,内存空间不在进程中,不属于任何进程

消息队列、共享内存、信号量 不属于任何进程 

消息队列是消息的链表,存放在内核中并由消息队列标识符表示

三:消息队列的使用

包含头文件:<sys/msg.h><sys/types.h>和<sys/ipc.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);//操作【如增删】

int msgget(key_t key, int msgflg);//【创建消息队列】

msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz,   long msg_typ, int msgflg);//接收

msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);//发送

msgget函数

作用:用来创建和访问一个消息队列

key: 某个消息队列的名字
msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
如果操作成功,msgget将返回一个非负整数,即该消息队列的标识码;如果失败,则返回“-1”

四:进程间通信 消息队列编程

查看msgget使用说明

返回:

成功(> -1)返回消息队列ID号/类型

-1则是出错/错误码

main.cpp

#include<iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>

using namespace std;

int main()
{
	if (msgget((key_t)1001, IPC_CREAT | 0777) == -1)
	{
		perror("msgget error");
	}
	else
	{
		cout << "消息队列创建成功" << endl;
	}
	return 0;
}

ipcs查看内存三剑客   可以看到消息队列创建成功

拥有者root 权限777 ,msqid是0  消息是0

将VS关闭程序运行,再次ipcs查看,消息队列的数据还在

说明了消息队列是由操作系统来管理 ,其内存空间也是由操作系统来管理,虽然进程关闭,但是消息队列还在

如果想要删除,使用 ipcrm,通过命令可以删除

ipcrm -h 可以查看 对于内存三剑客的操作

一般采取 ipcrm -a 初始化操作系统内存

根据手册提示 输入命名 ipcrm -q 0【按id号移除消息队列】

ipcs查看操作系统的内存,可以看出原先创建的消息队列已经被成功删除

对共享内存 消息队列 信号量 使用命令 ipcrm -a 来删除 最容易 

ipcrm -a 初始化操作系统内存

有些属于操作系统的内存不可被删除,如上图中 那些操作权限600,状态 2 的都是操作系统本身自带的 ,是不允许删除的

可以删除的只能是代码创建的,系统本身的内存是不可以被删除的

五:msgsnd函数 

msgsnd函数 

函数作用:把一条消息添加到消息队列里去

函数原型

int msgsnd(int msgid,const void *msg_ptr,size_t msg_sz,int msgflg);

msgid:由msgget函数返回的消息队列标识码

msg_ptr:是一个指针,指针指向准备发送的消息,

msg_sz:是msg_ptr指向的消息长度,这个长度不能保存消息类型的那个“long int”长整型计算在内

msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情

操作成功,返回“0”,如果失败,则返回“-1”

查看msgsnd使用说明 

msgbuf:必须指向固定要求的结构体

并且结构体  消息类型long型必须是>0   

同时 消息数据(char数据类型)

返回值:-1/错误码 是 失败 

main.cpp

#include<iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
#include<string.h>

using namespace std;

typedef struct msgsendbuf {
	long mtype;       /* message type, must be > 0 */
	char mtext[50];    /* message data */
}MSGBUF;


int main()
{
    //key_t如果不存在则创建,key_t如果存在则访问
	int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
	if (msgid == -1)
	{
		perror("msgget error");
	}
	else
	{
		cout << "消息队列创建成功" << endl;
	}

	MSGBUF buf;
	buf.mtype = 1;//设置消息类型
	strcpy(buf.mtext, "hello world");

	//发送消息
	if (msgsnd(msgid, &buf, sizeof(MSGBUF), 0) == -1)
	{
		perror("msgsnd error");
	}

	return 0;
}

已用字节数64 消息 1 ,已经发送消息成功

在VS中运行程序关闭进程,通过ipcs命令查看操作系统内存三剑客,消息队列仍然存在

做个测试:若消息队列不删除,再次运行一次程序

可以看出

字节数 128【发送一次64 发送二次128】   

消息 2 【发送2次】

对于msgget:key_t 如果不存在则创建,key_t 如果存在则访问

消息队列顺序 

队列:先进先出

尾部追加 头部删除

六:消息队列的发送与接收

消息队列的发送和接收,案例学习

初始化处理消息队列: 

命令 ipcrm -a            初始化操作系统内存       

命令 ipcs                   查看操作系统内存

查看msgcrv函数使用说明


消息队列的发送与接收,案例实现

发送 进程

main.cpp 

#include<iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
#include<string.h>

using namespace std;

typedef struct msgsendbuf {
	long mtype;       /* message type, must be > 0 */
	char mtext[50];    /* message data */
}MSGBUF;


int main()
{
	//key_t如果不存在则创建,key_t如果存在则访问
	int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
	if (msgid == -1)
	{
		perror("msgget error");
	}
	else
	{
		cout << "消息队列创建成功" << endl;
	}

	for (int i = 0; i < 3; i++)
	{
		MSGBUF buf;
		buf.mtype = 1;//设置消息类型
		sprintf(buf.mtext, "hello world %d", i);

		//发送消息
		if (msgsnd(msgid, &buf, sizeof(MSGBUF), 0) == -1)
		{
			perror("msgsnd error");
		}
	}
	return 0;
}

接收 进程

main.cpp

#include<iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
#include<string.h>

using namespace std;

typedef struct msgsendbuf {
	long mtype;       /* message type, must be > 0 */
	char mtext[50];    /* message data */
}MSGBUF;


int main()
{
	//key_t如果不存在则创建,key_t如果存在则访问
	int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
	if (msgid == -1)
	{
		perror("msgget error");
	}
	else
	{
		cout << "消息队列创建成功" << endl;
	}

	MSGBUF buf = { 0 };

	for (int i = 0; i < 3; i++)
	{
		if (msgrcv(msgid, &buf, sizeof(MSGBUF), 1, 0) < 0)
		{
			perror("msgrcv error");
		}
		else {
			cout << "buf.mtext = " << buf.mtext << endl;
		}
	}
	return 0;
}

g++ main.cpp -o main

./main

运行程序 生成进程 

消息队列创建成功 发送消息队列

ipcs查看内存

可以看出

消息队列 发送成功 

g++ main.cpp -o main

./main

运行程序 生成进程

可以看出

接收 消息队列 成功 

接收后  ipcs查看消息队列 

  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

chenruhan_QAQ_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值