当前位置:网站首页>IPC 通信 - IPC
IPC 通信 - IPC
2022-08-03 05:23:00 【纸鸢805】
现在linux使用的进程间通信方式:
(1)管道(pipe)和命名管道(FIFO)
(2)信号(signal)
(3)消息队列
(4)共享内存
(5)信号量 ( 1 ~ 5 是本地间通信 )
(6)套接字(socket) ( 网络之间 )
1. 消息队列
使用 ipcs 查看系统消息队列 、 共享内存段 、 信号量数组
这三者归 系统管理, 不属于进程管理。
作用:用来创建和访问一个消息队列
int msgget(key_t key, int msgflg);
参数:
key: 某个消息队列的名字 msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的 如果操作成功,msgget将返回一个非负整数,即该消息队列的标识码;如果失败,则返回“-1”
实际使用 例如:
发送端 : 发送的数据是一个固定的结构体
//消息结构体
typedef struct myxiaoxibuf {
long mtype; /* message type, must be > 0 */
char mtext[50]; /* message data */
}MYXIAOXIBUF;
int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror(" msgid error ! ");
}
else
{
cout << " 创建 msgid 成功!" << endl;
}
MYXIAOXIBUF buf = { 0 };
for (int i = 0; i < 3; i++)
{
char a[100] = { 0 };
sprintf(buf.mtext, "Hello %d", i);
buf.mtype = 1;
//添加一条信息进 消息队列
if (msgsnd(msgid, &buf, sizeof(MYXIAOXIBUF), 0) == 0)
{
cout << "发送成功!" << endl;
}
else if (msgsnd(msgid, &buf, sizeof(MYXIAOXIBUF), 0) == -1)
{
perror(" msgsnd error ! ");
}
}
return 0;
接收端: 接收端的 msgrcv 是一个阻塞函数如果消息队列没有消息则会停止运行
//消息结构体
typedef struct myxiaoxibuf {
long mtype; /* message type, must be > 0 */
char mtext[50]; /* message data */
}MYXIAOXIBUF;
int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror(" msgid error ! ");
}
else
{
cout << " 创建 msgid 成功!" << endl;
}
MYXIAOXIBUF buf = { 0 };
for (int i = 0; i < 3; i++)
{
if (msgrcv(msgid, &buf, sizeof(MYXIAOXIBUF), 1, 0) > 0)
{
cout << "接收成功 到的数据 = " << buf.mtext << endl;
}
else if(msgrcv(msgid, &buf, sizeof(MYXIAOXIBUF),1, 0) == -1)
{
perror(" msgsnd error ! ");
}
}
return 0;
需要删除的时候使用 ipcrm 。
1. 2 消息队列传递结构体
消息队列传递的是一个char 数组, 但是在传递的 char 数组如果足够大也可以用来容纳其他的结构体数据, 容纳的结构体数据可为 字符类型、 与实数类型, 不能使用string。以此特性来实现使用消息队列一个消息传递多条数据。
2. 共享内存
共享内存创建的内存也是一个 结构体。
2.1 流程:
1. 创建共享内存、 共享内存的结构体
2. 连接共享内存
3. 共享内存写入数据 / 读取数据
memcpy 内存拷贝 (读取与写入都是使用该方法)
memset 内存清空 (必要时读取后清空共享内存)
4. 关闭连接
2.2 使用 :
消息队列 与 共享内存 一般配套使用,完成完善的进程间通信。
共享内存写入:
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/msg.h>
using namespace std;
//共享内存存的结构体
typedef struct student
{
int stuid;
char stuName[20];
}STU;
//消息队列结构体
typedef struct msgbuf1 {
long mtype; /* message type, must be > 0 */
char mtext[50]; /* message data */
}MSGBUR1;
int main()
{
//创建一个共享内存, 如果该(key_t)1002存在则访问
int shmid = shmget((key_t)1002,sizeof(STU), IPC_CREAT | 0777 );
//共享内存地址
void* addres = NULL;
//接收的消息队列 结构体
MSGBUR1 msgbur1 = { 0 };
msgbur1.mtype = 1;
//发送接收成功的消息队列 结构体
MSGBUR1 msgbur2 = { 0 };
msgbur2.mtype = 2;
//创建接收的消息队列
int msgid = msgget((key_t)1003, IPC_CREAT | 0777);
//创建发送接收成功的消息队列
int msgid2 = msgget((key_t)1004, IPC_CREAT | 0777);
if (msgid == -1)
{
perror(" msgid error ! ");
}
else
{
cout << " 创建 msgid 成功!" << endl;
}
if (msgid2 == -1)
{
perror(" msgid2 error ! ");
}
else
{
cout << " 创建 msgid2 成功!" << endl;
}
if (shmid == -1)
{
perror(" shmget error ! ");
}
else
{
cout << "共享内存创建成功!" << endl;
int xiaoxinum = 0; //发送消息的次数
STU stu = {0};
//链接共享内存
addres = shmat(shmid, NULL,IPC_CREAT | 0777 );
while (1)
{
stu.stuid = 101 + xiaoxinum;
sprintf(stu.stuName, "益达%d", xiaoxinum);
//写出数据到共享内存
memcpy(addres, &stu, sizeof(STU));
//改变发送的消息信息
sprintf(msgbur1.mtext, " A 写入共享内存结束 :%d 次", ++xiaoxinum);
//添加消息进队列
if (msgsnd(msgid, &msgbur1, sizeof(MSGBUR1), 0) == 0)
{
cout << " A 发送成功!" << xiaoxinum << "次" << endl;
}
else if (msgsnd(msgid, &msgbur1, sizeof(MSGBUR1), 0) == -1)
{
perror(" msgsnd error ! ");
}
//接收消息队列信息
msgrcv(msgid2, &msgbur2, sizeof(MSGBUR1), 2, 0);
cout << "B 的信息反馈 = " << msgbur2.mtext << endl;
}
//断开与共享内存的连接
//shmdt(addres);
}
return 0;
}
共享内存读取:
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
using namespace std;
//共享内存存的结构体
typedef struct student
{
int stuid;
char stuName[20];
}STU;
//消息队列结构体
typedef struct msgbuf1 {
long mtype; /* message type, must be > 0 */
char mtext[50]; /* message data */
}MSGBUR1;
int main()
{
//创建一个共享内存, 如果该(key_t)1002存在则访问
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT | 0777);
//共享内存地址
void* addres = NULL;
//接收的消息队列 结构体
MSGBUR1 msgbur1 = { 0 };
msgbur1.mtype = 1;
//发送接收成功的消息队列 结构体
MSGBUR1 msgbur2 = { 0 };
msgbur2.mtype = 2;
//创建接收的消息队列
int msgid = msgget((key_t)1003, IPC_CREAT | 0777);
//创建发送接收成功的消息队列
int msgid2 = msgget((key_t)1004, IPC_CREAT | 0777);
if (msgid == -1)
{
perror(" msgid error ! ");
}
else
{
cout << " 创建 msgid 成功!" << endl;
}
if (msgid2 == -1)
{
perror(" msgid2 error ! ");
}
else
{
cout << " 创建 msgid2 成功!" << endl;
}
if (shmid == -1)
{
perror(" shmget error ! ");
}
else
{
cout << "共享内存创建成功!" << endl;
STU stu = { 0 };
stu.stuid = 10086;
sprintf(stu.stuName, "益达1");
//链接共享内存
addres = shmat(shmid, NULL, IPC_CREAT | 0777);
int xiaoxinum = 0; //发送消息的次数
while (1)
{
//接收消息队列信息
msgrcv(msgid, &msgbur1, sizeof(MSGBUR1),1, 0);
cout << " B 接收到消息 = " << msgbur1.mtext << endl;
//写入共享内存数据到stu
memcpy(&stu, addres, sizeof(STU));
cout << "stu.stuid 的值为: " << stu.stuid << endl;
cout << "stu.stuName 的值为: " << stu.stuName << endl;
//清空共享内存数据
memset(addres, 0, sizeof(STU));
//改变发送的消息信息
sprintf(msgbur2.mtext, " B 已接收到数据 :%d 次", ++xiaoxinum);
//添加消息进队列
msgsnd(msgid2, &msgbur2, sizeof(MSGBUR1), 0);
sleep(2);
}
//断开与共享内存的连接
//shmdt(addres);
}
return 0;
}
3 . 总结:
信号:
缺点 : 信号冲突、 信号屏蔽 ( 如果进程接收到一个不认识的信号会导致进程直接暴毙 )
优点 : 有优点,但是不多(就是鸡肋), 可以做到简单的数据传输(只能 int 类型数据), 做到进程之间的通知效果。
管道 :
优点: 传输的数据于文件IO类似, 传输的数据可以有多种类型, 因为 write 写入的数据参数是 void * 类型的。
缺点: 传输的数据量有上限; 命名管道的文件会显示出来可能被误删掉。
消息队列:
优点:队列中的消息有顺序, 虽然名字是队列但是实际上是链表构成,一直读取链表头的数据, 读取完之后系统自动释放掉头结点。
缺点: 与管道一样有传输数据量有上限, 系统全体队列、队列的结构体是固定的。
共享内存:
优点: 传递数据的效率是最高的, 而且传递的数据类型没有限制, 实质上是在系统内存中存储数据。
缺点: 共享内存中是否存放数据无法直接观察到, 而且使用memcpy是非阻塞函数,会造成多进程、多线程操作存在数据不安全的问题。
边栏推荐
猜你喜欢
vivado遇到的问题
Qlik Sense 判空详解(IsNull)
【DC-5 Range Penetration】
Go (一) 基础部分3 -- 数组,切片(append,copy),map,指针
Django从入门到放弃三 -- cookie,session,cbv加装饰器,ajax,django中间件,redis缓存等
Gradle插件与代理服务器导致Sync Project失败的问题
Let small program development into ` tailwind jit ` era
嵌入式实验三(代码几乎都要改才能运行)
当奈飞的NFT忘记了web2的业务安全
滚动条 scrollbar 和scrollbar-thumb 样式
随机推荐
arm64麒麟安装paddlehub(国产化)注意事项
Oracle 密码策略详解
联邦学习摘录
[frp intranet penetration]
Go (二) 函数部分1 -- 函数定义,传参,返回值,作用域,函数类型,defer语句,匿名函数和闭包,panic
Sqli-labs-master shooting range 1-23 customs clearance detailed tutorial (basic)
【Yarn】yarn常用命令 查看日志和Kill任务
jsp通过form表单提交数据到servlet报404
中国融资租赁行业市场投资分析与前景战略规划建议报告2022~2028年
嵌入式实验二
controller层到底能不能用@Transactional注解?
中国石油行业并购重组趋势与投资战略规划建议报告2022~2028年
Delightful Nuxt3 Tutorial (1): Application Creation and Configuration
东南亚跨境电商
Oracle null 有哪些注意事项【面试题】
代码没写完,哪里有脸睡觉!17 张程序员壁纸推荐
SAP HANA 新增一列时报错详解
Leetcode刷题——一些用层次遍历解决的问题(111. 二叉树的最小深度、104. 二叉树的最大深度、226. 翻转二叉树、剑指 Offer 27. 二叉树的镜像)
【反弹shell与提权】
Haproxy服务监控