Linux之进程间通信(下)

news2024/11/15 19:35:34

目录

命名管道

命名管道的创建

匿名管道和命名管道的区别

命名管道的代码实现

共享内存 

创建共享内存

关联共享内存

去关联共享内存 

删除共享内存 

共享内存特点 

共享内存代码实现 

IPC资源总结


命名管道

上期我们学习了匿名管道,匿名管道本质就是一个文件,且匿名管道适用于有血缘关系的进程进行通信,那如果有两个没有血缘关系的进程,那么这两个进程该如何进行通信呢?这就需要我们今天学习的命名管道,命名管道适用于没有血缘关系的两个进程进行通信。

我们知道,两个进程要进行通信的前提就是两个进程看到同一份资源,所以对于两个没有血缘关系的进程,通信的前提就是让这两个进行看到同一份资源。所以我们就需要创建命名管道,命名管道本质上也是文件。

命名管道的创建

命名管道有两种创建方法。

  1. 在命令行输入指令进行创建:mkfifo 管道名称
  2. 在程序中进行创建:int mkfifo(const char* filename,mode_t mode),第一个参数为创建的管道的路径,第二个为管道的访问权限,因为命名管道也是一个文件。

匿名管道和命名管道的区别

  1. 匿名管道使用pipe函数进行创建并打开
  2. 命名管道使用mkfifo函数进行创建,使用open函数打开。
  3. 因为命名管道和匿名管道本质都是文件,所以打开之后,后续的进程的读写操作都是类似的。

在这里声明一下,按照正常的操作流程,文件的读写如上图所示,写文件时,进程1先调用系统接口wirte()将要写的数据舒心到内核缓冲区,然后调用驱动中的接口write()将数据最终刷新到文件中,写完毕。进程2读文件时操作系统先把底层文件中的数据通过驱动中的read()接口读取到文件内核缓冲区,然后进程2调用read()接口从文件缓冲区中读取到数据,读完毕。

上面的操作步骤是一个正确完整的步骤,但是对于进程间通信而言,使用匿名管道和命名管道进行通信时,并不像上述的操作步骤一样进行读写,而是写时不去调用驱动中的接口刷新到底层文件,读时不从底层文件读取到文件内核缓冲区,省去了底层文件的交互,转化为从文件内核缓冲区中进行交互,这样可以大大的提升效率。

命名管道的代码实现

sever端口进行命名管道的创建以及数据的读取。代码如下

#include"comm.h"


int main()
{

  //创建匿名管道
  if(mkfifo(PATH,0666)<0)
  {
    perror("mkfifo");
    return 1;
  }
  
  //创建管道成功,打开管道
  int fd=open(PATH,O_RDONLY);
  if(fd<0)
  {
    perror("open");
    return 2;
  }

  //进行读取操作
  char buff[64]={0};
  while(1)
  {
    int num=read(fd,buff,sizeof(buff)-1);
    
    if(num>0)
    {
      printf("%s\n",buff);
    }
    else if(num==0)
    {
      perror("client quit");
      break;
    }
    else{
     perror("read");
     break;
    }
  }

  close(fd);
  return 0;
}

client端口进行命名管道中数据的写入。

#include"comm.h"
#include<string.h>

int main()
{

  //sever端已经创建了命名管道,client只需要打开即可
  //打开文件
  int fd=open(PATH,O_WRONLY);
  if(fd<0)
  {
    perror("open");
    return 1;
  }

  //client端进行写操作
  const char* msg="hello yjd";
  while(1)
  { 
  write(fd,msg,strlen(msg));
  }


  close(fd);
  return 0;
}

comm.h中存放client和sever端需要的头文件以及生成的命名管道路径。

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>


#define PATH "./fifo"

 运行结果如下。

我们发现sever端口确实读取到了client端口写入的数据。

共享内存 

共享内存是基于system v标准下的一个IPC资源。无论是匿名管道还是命名管道,本质上都是基于文件的共享资源。而共享内存则是基于内存的,相当于在内存中开辟了一块空间作为两个进程的公共资源。示意图如下。

总体来说,操作系统在内存中申请一块空间作为共享内存,然后通过页表映射到进程的虚拟地址空间中,此时站在进程的角度就可以通过使用虚拟地址空间中的内存达到了访问共享内存的目的。 

但是与此同时也产生了几个问题。站在用户的角度,怎么创建共享内存?两个进程怎样和共享内存关联起来,又怎样去除关联?怎样删除共享内存? 下来我们一一解答。这个四个问题刚好也是操作共享内存的整个流程。

创建共享内存

形参含义:key为在操作系统层面识别唯一共享内存的一个值。size为创建的共享内存的大小一般为一页4KB,shmflg为一个标记值,当shmflg为IPC_CREATE时,为创建一个共享内存,如果当前-+key值对应的共享内存不存在则创建,存在则返回存在的共享内存。当shmflg为IPC_CREATE|IPC_EXCL时,为如果key值所对应的共享内存不存在则创建,存在在返回错误码。

返回值:如果创建成功则返回一个id,这个id为一个标识码,可用于用户识别唯一共享内存。 失败返回-1。

其中的key值我们一般使用ftok函数进行获取。

形参含义:pathname为我们随意指定的一个路径,proj_id为我们随意制定的一个整型。

返回值:成功则返回一个key值,用于操作系统标识唯一共享内存。失败则返回-1。 

关联共享内存

形参含义: shmid为创建共享内存成功时返回的值,即共享内存对于用户的唯一标识。剩下两个参数不用了解,无脑NULL和0即可。

返回值:若进程关联共享内存成功,返回值为共享内存映射到进程虚拟地址空间中的首地址,失败则返回-1。

去关联共享内存 

形参含义:shmaddr为关联共享内存函数shmat的返回值。

返回值:成功返回0,失败返回-1。 

删除共享内存 

形参含义:shmid为创建共享内存时的返回值。cmd设置为IPC_RMID即可,最后一个buf默认设置为空即可。

返回值:成功则返回0,失败返回-1。 

共享内存特点 

  1. 共享内存的生命周期是随着操作系统的内核的。而之前的命名和匿名管道都是文件,文件都是由进程打开的,所以命名和匿名管道的周期都是随进程的。

  2. 共享内存中数据的读写不需要任何缓冲区,写端一写,读端就立即可以读。所以共享内存是进程间通讯速度最快的一种通信方式。

共享内存代码实现 

sever端口创建共享内存,并进行数据的读取。

#include"comm.h"
#include<unistd.h>

int main()
{
  //获取key
  key_t key=ftok(PATH,NUM);
  if(key<0)
  {
    perror("ftok");
    return 1;
  }
  printf("ftok success\n");
  //创建共享内存 
  int id = shmget(key,SIZE,IPC_CREAT|IPC_EXCL|0666);
  if(id<0)
  {
    perror("shmget");
    return 2;
  }

  printf("shmget success\n");

  //创建成功,进程1绑定共享内存 
  char* mem=(char*)shmat(id,NULL,0);
  printf("shmat success\n");

  //逻辑操作
  while(1)
  {
    sleep(3);
    printf("%s\n",mem);
  }


  //去关联共享内存
  shmdt(mem);

  //删除共享内存
  shmctl(id,IPC_RMID,NULL);


  return 0;
}

client端进行数据的写入。

#include"comm.h"
#include<unistd.h>



int main()
{
  //得到一个key值,这个key必须与sever端的key值一样,才能保证得到相同的共享内存
  key_t key=ftok(PATH,NUM);
  if(key<0)
  {
    perror("ftok");
    return 1;
  }
  //得到一个与sever端相同的共享内存
  int id=shmget(key,SIZE,IPC_CREAT);
  if(id<0)
  {
    perror("shmget");
    return 2;
  }

  //进程2绑定共享内存
  char* mem=(char*)shmat(id,NULL,0);
  printf("shmat success\n");
  //处理业务逻辑
  char ch='A';
    while(ch <= 'Z')
    {
        mem[ch-'A'] = ch;
        ch++;
        mem[ch-'A'] = 0;
        sleep(2);
    }

  //去关联共享内存
  shmdt(mem);

  //共享内存的删除进程2不用参与,因为进程1创建并删除共享内存

  return 0;
}

comm.h中存放client端和sever端需要的头文件。

#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>


#define PATH "./"
#define NUM  0x6666
#define SIZE 4096

运行结果如下。

运行结果符合预期。

以上便是共享内存的所有内容。

IPC资源总结

共享内存,消息队列和信号量,其实他们都是system V标准下的IPC资源,只要是IPC资源,那么操作这些资源的接口以及描述这些资源的数据结构就都一定是类似的。

在内存中,操作系统创建共享内存可能有多个,操作系统为了讲这些共享内存管理起来,按照先描述,后组织的六子真言,操作系统创建了shmid_ds类型的结构体用来描述共享内存,这个结构体的第一个成员变量struct ipc_perm也是一个结构体,第一个成员变量就是操作系统表示唯一共享内存的一个值。

消息队列的结构体如上图,我们发现与共享内存相似。 

信号量的结构体如上图,与共享内存也相似,所以这也验证了IPC资源的接口与结构体类似的结论。至于为什么类似,是因为底层有一个指针数组,是struct ipc_perm* arr[N]类型的指针数组,首先把每个IPC资源的结构体对象的地址强转为struct ipc_perm*类型赋值给指针数组的元素,最终访问IPC资源所对应的结构体时,指针数组的元素会被强转为对应结构体类型的指针变量去访问对应类型的结构体的成员变量。

以上便是进程间通信的所有知识点。

本期内容到此结束^_^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2039213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EcoVadis评估对可持续发展具体表现在哪些方面

Ecovadis认证是一项备受推崇的环保和社会责任认证&#xff0c;其优势不仅在于其权威性和公信力&#xff0c;更在于其全面而深入的评估标准&#xff0c;这个认证体系将企业划分为不同的等级&#xff0c;从入门级的银牌到最高级别的白金级&#xff0c;每个等级都有相应的评估标准…

Selenium + Python 自动化测试14(发送报告)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了使用HTMLTestRunner 生成HTML报告的方法。 本篇文章我们接着讲生成HTML报告是否可以自动邮件发送出去&#xff0c;提高我们测试报告的及时性&#xff0c;方便…

PCB入门笔记—绘制一个只有两个排针的PCB全流程记录—立创EDA专业版

PCB绘制入门&#x1f680; 硕士毕业之后准备进入博士阶段&#xff0c;本科阶段做的硬件&#xff0c;硕士阶段做的算法&#xff0c;然后博士阶段又要做回硬件了&#xff0c;因此也是打算补一补PCB相关的内容和知识&#xff0c;毕竟做控制的话&#xff0c;之后这也是不能躲开的必…

前端工程化-02.Yapi接口管理平台

YApi Pro-高效、易用、功能强大的可视化接口管理平台 图片中链接已失效&#xff0c;此处为新链接 选择添加接口&#xff0c;输入接口名称和接口路径。 创建成功后自动进入接口页面&#xff0c;点击编辑&#xff0c;可以编辑完善这个接口的信息。两个非常重要的信息&#xff1a…

进程waitwaitpid、线程

一、wait wait功能 1、获取子进程退出状态&#xff0c;分析子进程是否已经退出&#xff08;变成僵尸态&#xff09; 2、回收资源&#xff0c;让僵尸态子进程销毁 wait本身是一个阻塞操作&#xff0c;会使调用者阻塞 2、宏&#xff1a; &#xff08;1&#xff09;WIFEXITE…

bug的常见排查和分析思路以及相关的原因分类

作为开发人员&#xff0c;经常会收到来自用户和QA&#xff0c;领导反馈的各种问题。 为了快速问题&#xff0c;我们有时需要站在更高的角度&#xff0c;更全面的看待问题。才能更快锁定问题。 具体的bug还需要结合企业实际业务情况&#xff0c;相关的框架&#xff0c;依赖库&…

海康摄像头(测温型)桌面客户端开发分享

分享一个自己开发的用于企业特殊场景下温度监控告警的一个桌面应用。 关键功能&#xff1a; 1.支持海康摄像头&#xff1b; 2.支持多路视频预览&#xff0c;多通道画面选择预览&#xff0c;支持视频画面回放与下载&#xff1b; 3.支持自动探测摄像头功能&#xff0c;若具备…

RabbitMQ集群部署

RabbitMQ集群部署 简介 消息中间件RabbitMQ&#xff0c;一般以集群方式部署&#xff0c; 主要提供消息的接受和发送&#xff0c;实现各微服务之间的消息异步。 以下将介绍RabbitMQHA方式进行部署。 原理介绍 cookie ​ RabbitMQ底层是通过Erlang架构来实现的&#xff0c;所…

基于java五台山景点购票系统(源码+论文+部署讲解等)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台的优…

自建Gitlab和Gitlab runner并推送镜像到Harbor

1. 创建虚拟机 整体规划如下 1.1 创建3台虚拟机 系统版本Centos7.9 设置IP分别为 192.168.200.201 、192.168.200.202、 192.168.200.203 1.2 安装docker 3台虚拟机都安装docker&#xff0c;参考文章 安装docker 1.3 修改daemon.json 修改 /etc/docker/daemon.json 文件…

【数字信号处理】第3章 离散时间信号和系统的频域分析,系列的离散时间傅里叶变换,性质,定理(清华大学)

目录 第3章 离散时间信号和系统的 引言 信号和系统的分析方法有两种 模拟信号与系统的时域分析 模拟信号与系统的频域分析 离散时间信号和系统 历史回顾 3.1.1 序列的离散时间傅里叶变换 3.1.2 序列的离散时间傅里叶变换的性质 1. DTFT的周期性 2. 线性 3. 时移(位移…

守护网站心脏:HAProxy负载均衡技术详解(全网最详细)

守护网站心脏&#xff1a;HAProxy负载均衡技术详解 文章目录 **守护网站心脏&#xff1a;HAProxy负载均衡技术详解**haproxy介绍特点功能配置结论 haproxy负载均衡测试haproxy主机操作日志重定向操作 webserver1主机操作webserver2主机操作 haporxy相关配置测试backup参数测速h…

Petalinux 使用相关问题

文章目录 Petalinux 交叉编译环境Petalinux 以太网相关Petalinux 应用层写寄存器操作 Petalinux 交叉编译环境 方法一&#xff1a; 注意&#xff1a;该方法安装时会 和 Petalinux的 gcc-multilib 冲突&#xff1b; sudo apt install cmake sudo apt-get install gcc-arm-lin…

网络协议 十一 ARP,RARP,icmp,websocket,webservice,HTTPDNS,FTP,邮件相关的协议, SMTP,POP,IMAP

ARP 已知IP 求 MAC 的过程 RARP 已知MAC 求 IP 的过程&#xff0c;已被DHCP取代 ICMP websocket 协议&#xff0c;html5中提出的前端使用协议 webservice 技术&#xff0c;已过时 HTTPDNS 之前我们要获得 某一个域名的 IP &#xff0c;要通过DNS协议 去 运营商的ISP 查询&…

Java | Leetcode Java题解之第327题区间和的个数

题目&#xff1a; 题解&#xff1a; class Solution {public int countRangeSum(int[] nums, int lower, int upper) {long s 0;long[] sum new long[nums.length 1];for (int i 0; i < nums.length; i) {s nums[i];sum[i 1] s;}return countRangeSumRecursive(sum,…

我对意义产生了怀疑!当今社会,一个最基本的因果律(深度好文)——早读(逆天打工人爬取热门微信文章解读)

有时候热搜也是一种预示 引言Python 代码第一篇 洞见 当今社会&#xff0c;一个最基本的因果律&#xff08;深度好文&#xff09;第二篇 空仓结尾 引言 今天真的晚 不过今天会更新两篇 破事真的多 有些人真的很神奇 在你做的时候不断来干预你 然后做得一般的时候就说 你的计划…

计算机图形学 | 动画模拟

动画模拟 布料模拟 质点弹簧系统&#xff1a; 红色部分很弱地阻挡对折 Steep connection FEM:有限元方法 粒子系统 粒子系统本质上就是在定义个体和群体的关系。 动画帧率 VR游戏要不晕需要达到90fps Forward Kinematics Inverse Kinematics 只告诉末端p点&#xff0c;中间…

Simple RPC - 03 借助Netty实现异步网络通信

文章目录 Pre设计技术点1. 接口设计2. 命令类设计3. 异步通信4. 异常处理与超时机制5. 背压机制6. 响应处理 Code封装通信 Transport 接口抽象数据的请求和响应 Command关于版本号 Transport 接口实现类 NettyTransport兜底的超时机制 背压机制 实现 总结 Pre Simple RPC - 01…

ComfyUI中,“鼠标忽然不太好用了”的解决方案---新版本偶遇bug

&#x1f387;背景 这是个很奇怪的界面bug。 最近几天感觉Comfyui的界面操作不好用了&#xff0c;就是鼠标移动到一个节点上&#xff0c;如果想要缩放&#xff0c;按道理应该是在1的位置&#xff0c;但是需要移动到2的位置才能触发缩放的操作。 节点连线的时候&#xff0c;线…

图纸变更频繁,版本管理的高效方法

在工程设计领域&#xff0c;图纸作为设计与制造的核心载体&#xff0c;其变更频繁性已成为常态。如何高效地管理这些不断变化的图纸版本&#xff0c;确保设计信息的准确性和一致性&#xff0c;是每个设计团队面临的重要挑战。本文将探讨几种高效管理图纸版本的方法&#xff0c;…