【linux】 Linux 匿名管道:从 pipe 调用到通信测试(可运行代码 + 原理剖析)

【linux】 Linux 匿名管道:从 pipe 调用到通信测试(可运行代码 + 原理剖析)
前言:欢迎各位光临本博客,这里小编带你直接手撕**,文章并不复杂,愿诸君**耐其心性,忘却杂尘,道有所长!!!!
在这里插入图片描述

IF’Maxue个人主页
 🔥 个人专栏:
《C语言》
《C++深度学习》
《Linux》
《数据结构》
《数学建模》

⛺️生活是默默的坚持,毅力是永久的享受。不破不立!

文章目录

为什么要通信

  • 数据传输:进程间传递信息
  • 资源共享:多个进程共用一份资源
  • 通知事件:一个进程告知另一个进程发生了特定事件
  • 进程控制:管理其他进程的运行状态

怎么通信

  • 进程间通信的本质:让不同进程先“看到”同一份资源,有了这个基础才能通信
  • 这份“内存”不能由任何进程自己提供,必须由操作系统分配——我们通过系统调用来操作这份内存,同时还要约定好通信的标准。
  • 写代码前,得先定好通信的“规矩”(标准)。
    • 关于“标准”:
      • 制定标准往往需要竞争:某个公司在技术上形成绝对领先,才能让其他公司认可并遵循。
      • 新技术一定会催生新的行业形态。
      • 从内卷、跟风到全员遵循,最终形成统一标准。

什么是通信

概念:

进程间通信,简单说就是运行在同一台或不同计算机上的多个进程,进行数据交换的技术。

每个进程都有自己的地址空间,无法进行彼此间的访问,我们借助一个机制来实现他们间的访问就叫做通信

这里我们只是提及一下具体通信概念,并不深入,后续网络部分会细讲这两个通信方式

  • 具体通信方式
    • 基于文件的:管道通信
    • System V:本机内进程通信
匿名管道(基于血缘关系的通信)

背景:
我们把视角拉到通信的起源,当时各个工程师只是界定好了进程的概念,但是他们遇到一个棘手的事情,这些进程只能各自运行各自的,两个进程之间无法进行数据沟通,首先关注的进程就是父子进程之间的通信,经过机制的设计和商讨,诞生了匿名管道机制

  • 早期的进程通信多基于文件,管道就是其中一种。
  • 管道结构示意图:
  • 匿名管道:主要用于父子进程间的通信和具有血缘关系的进程之间的通信,看下方的结构图,我们知道,子进程是以父进程为模板进行运行的,大部分的数据和代码拷贝于父进程。
    • 父进程的mm_struct中有一块指针指向fd_array文件描述符表,从下标3开始每一块磁盘文件都有着自己的struct_file统一在fd_array中进行管理。
    • 子进程的fd_array文件描述表都拷贝于父进程的,但是在文件管理中的文件内容不需要进行拷贝。
  • 父子进程的文件描述表(记录打开文件信息的表)是相同的,它们共享同一个文件结构体(struct file)。
在这里插入图片描述
  • 们把让不同进程“看到”同一份资源的载体,称为管道
  • 虚拟示意图(注意:缓冲区不算管道本身):
  • 管道是内存级的,和磁盘没有关系。不存在于磁盘当中
原理
  • 匿名管道通常用于父子进程的单向通信。
  • 我们对匿名管道进行讲解:
    • 父进程创建管道,同时接入读写端
    • fork出子进程,也接入子进程的读写端
    • 根据需要关闭父子进程的读写端
    • 创建管道
    • 父子进程同时“接入”管道
    • 关闭不需要的读写端
  • 管道是操作系统单独设计的(可复用代码),通过专门的系统调用pipe创建(pipe是输出型参数)。

在管道中我们就可以实现两者的交互,这就好比讲话的例子,一个人输出,一个人输入才能时间交互。管道就相当于空气—传播渠道

通信步骤:

匿名管道没有路径和文件名,只存在于内存中,因此称为“匿名”

  • 如何保证两个进程打开的是同一个管道?
    子进程会继承父进程的文件描述符表,因此能共享同一个管道。
代码测试

核心目标:让不同进程(这里是父子进程)看到同一份资源(管道)。

先看一个简单的测试:创建管道后,打印管道的读写端文件描述符。

#include<iostream>#include<unistd.h>intmain(){int fds[2]={0};int n =pipe(fds);if(n <0){ std::cerr <<"pipe error"<< std::endl;return1;} std::cout <<"fds[0]: "<< fds[0]<< std::endl; std::cout <<"fds[1]: "<< fds[1]<< std::endl;return0;}

预期结果:父进程和子进程打印的文件描述符都是3(读端)和4(写端)。

实际运行结果:

说明父子进程确实共享了同一个管道的文件描述符。

通信测试:子写父读

步骤解析:

  1. 创建管道:用pipe函数,得到fds[0](读端)和fds[1](写端)。
  2. 创建子进程:用fork,子进程继承父进程的文件描述符表。
  3. 关闭不需要的端:父进程关闭写端(fds[1]),子进程关闭读端(fds[0])(管道是文件,不用的端要及时关闭,避免资源浪费)。

代码示例(核心逻辑):

#include<stdio.h>#include<unistd.h>#include<string.h>intmain(){int fds[2];// 1. 创建管道if(pipe(fds)<0){perror("pipe error");return1;}// 2. 创建子进程pid_t pid =fork();if(pid <0){perror("fork error");return1;}if(pid ==0){// 子进程:写数据// 关闭读端(子进程只写)close(fds[0]);char buf[128];snprintf(buf,sizeof(buf),"hello, father! I'm child, pid: %d",getpid());// 系统调用write不会自动加\0,需要确保数据长度正确write(fds[1], buf,strlen(buf));close(fds[1]);// 写完关闭写端}else{// 父进程:读数据// 关闭写端(父进程只读)close(fds[1]);char buf[128]={0};// 初始化,方便后续打印时自动识别字符串结尾ssize_t n =read(fds[0], buf,sizeof(buf)-1);// 留一个位置给\0if(n >0){ buf[n]='\0';// 手动加\0,确保字符串完整printf("father read: %s\n", buf);}close(fds[0]);// 读完关闭读端}return0;}

注意点:

  • C语言的sizeof计算字符串长度时会包含\0,但系统调用(如writeread)不会自动处理\0,需要手动添加。
  • 运行结果:
  • 子进程写入的数据,父进程成功读取:

Read more

AJAX与Fetch--异步Web请求的对比

AJAX与Fetch--异步Web请求的对比

在当今的Web开发中,异步数据获取早已成为构建动态应用的核心能力。从早期的AJAX技术到现代的Fetch API,开发者面对的选择越来越多。然而,这两种主流技术究竟有何不同?在实际项目中该如何选择?让我们从解决问题的角度出发,深入剖析它们的差异与适用场景。 AJAX:技术本质与核心原理 AJAX(Asynchronous JavaScript and XML)这一术语由Jesse James Garrett于2005年提出,它并非单一技术,而是一套技术集合的统称——包括XMLHttpRequest对象、DOM操作、JavaScript以及XML或JSON数据格式。这种组合拳使得网页能够在不刷新的情况下与服务器交换数据,从而带来了Web 2.0时代的革命。 // 传统AJAX请求示例 const xhr = new XMLHttpRequest();   xhr.open('GET', '/api/data', true);   xhr.onreadystatechange = function() {   if (xhr.readyState

By Ne0inhk

go语言:实现password generator复杂密码生成器算法(附带源码)

项目背景详细介绍 在现代软件系统中,“密码(Password)”依然是最基础、最常见的身份认证手段之一。 无论是: * Web 系统登录 * 数据库访问凭证 * API Key * 运维账号 * 内部管理系统 几乎都绕不开一个核心问题: 如何生成一个“足够安全”的密码? 现实中,弱密码问题长期存在: * 使用生日、手机号 * 使用 123456、password * 使用单一字符集(纯数字 / 纯小写) * 密码长度过短 这些问题直接导致: * 暴力破解成功率极高 * 字典攻击几乎零成本 * 内部系统被轻易入侵 因此,“复杂密码生成器(Password Generator)”成为了安全体系中的一个基础组件。 通过算法自动生成: * 长度足够 * 字符类型丰富 * 分布均匀 * 不可预测 的密码,是提升系统整体安全性的第一道防线。 项目需求详细介绍 本项目的目标是: 使用 Go 语言实现一个可配置的复杂密码生成器算法(

By Ne0inhk
数据结构:单链表(2)

数据结构:单链表(2)

目录 前言  一、实现单链表 介绍: 1.链表节点查找 2.链表在指定位置之前或之后插入元素 (1)链表在指定位置之前插入元素 举实例: (2)链表在指定位置之后插入元素 3.链表在指定位置删除或指定位置之后删除 (1)链表在指定位置删除 (2)链表在指定位置之后删除 三、举实例,测试代码(包括所有代码展现) 1.h 1.cpp main.cpp 四、链表的分类 按节点连接方向分类 按是否有头节点分类   总结 前言  上篇文章讲解了单链表的知识,包括:单链表的概念,单链表的结构、实现单链表(单链表的尾插、单链表的头插、单链表的尾删、单链表的头删)知识的相关内容,实现单链表其余的函数、链表的分类、单链表算法题知识的相关内容,为本章节知识的内容。

By Ne0inhk