Linux:匿名管道(进程间通信二)

今天我们来讲讲管道之一的匿名管道,话不多说,我们正式开始啦

1.什么是管道

管道是Unix中最古⽼的进程间通信的形式,我们把从⼀个进程连接到另⼀个进程的⼀个数据流称为⼀个"管道"

在最开始的时候,其实顶尖大佬并不打算创建一个新的东西来进行管道通信,而是打算采用现有的东西来解决进程间通信的问题,于是他们就想到了文件,对于父子进程来说,父子进程有同样的struct file,来指向同一个被打开的文件,而对于一个文件来说,他有自己的缓冲区,是不是可以让父进程将内容写入文件缓冲区,让子进程通过fd来找到这个文件,并且读取缓冲区文件内容,反之亦然,从而实现了进程间的通信,这就是管道的雏形,并且由此衍生出了匿名管道与命名管道

2.匿名管道

1.原理

看上图,父进程由*files指向files_struct,也就是文件描述符表,现在我们打开一个文件,fd = 3,对于打开的文件,该文件内容被存放在arrayfd中,我们创建一个子进程,子进程继承父进程的*files,files_struct等等,此时父子进程的指针指向同一块地方,也就是被打开的文件,于是父子进程同时可以访问该文件的缓冲区,或许你会疑问,被打开文件最后不是还要写回磁盘吗,其实真正的管道是由OS创建的一块内存,不需要刷回磁盘,和磁盘没关系,这也符合通信间的本质!!

所以真实的底层差不多是上图的样子,父进程使用pipe函数生成内存级通道,创建的子进程也可以通过fd指向此通道,此时关闭父进程的fd3与子进程的fd4,这就是进程之间的通信--单向通信,而pipe过程不需要文件路径,只需要一个pipefd2数组,没有文件名,所以此过程被称为匿名通信

2.pipe函数

通过man 2 pipe可以查看该系统函数

成功创建通道返回0,反之-1

对于成功创建的管道,pipefd2应该保存fd可读fd可写

3.pipe函数简单运用

testPipe.cc:

cpp 复制代码
#include <iostream>
#include <unistd.h>

int main()
{   
    int pfd[2] = { 0 };
    int n = pipe(pfd);
    if (n == -1)
    {
        std::cerr <<  "pipe error!" << std::endl;
        return 1;
    }
    std::cout << "pfd[0] : " << pfd[0] << std::endl;
    std::cout << "pfd[1] : " << pfd[1] << std::endl;
    return 0;
}

运行结果如下:

为什么是3与4呢,因为fd = 0,1,2已经被标准输入输出错误占据了

3.实现一个简易的父子进程管道通信

testPipe.cc:

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>

void ChildWrite(int wfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        snprintf(buffer, sizeof(buffer), "我是子进程, pid : %d, cnt : %d", getpid(), cnt++);
        write(wfd, buffer, strlen(buffer));
        sleep(1);
    }
}

void FutherRead(int rfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer << std::endl;
        }
    }
}

int main()
{
    // 创建管道
    int pfd[2] = {0};
    int n = pipe(pfd);
    if (n == -1)
    {
        std::cerr << "pipe error!" << std::endl;
        return 1;
    }
    std::cout << "pfd[0] : " << pfd[0] << std::endl;
    std::cout << "pfd[1] : " << pfd[1] << std::endl;
    // 一般来说,pfd[0] -> 读端   pfd[1] -> 写端
    // 创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        // 关闭子进程读端
        close(pfd[0]);

        // 子进程向管道写入内容
        ChildWrite(pfd[1]);

        // 关闭子进程写端
        close(pfd[1]);
    }
    // 关闭父进程写端
    close(pfd[1]);

    // 父进程读取管道内容
    FutherRead(pfd[0]);

    // 等待子进程结束
    waitpid(id, nullptr, 0);

    // 关闭父进程读端
    close(pfd[0]);
    return 0;
}

运行结果如下:

好啦,这就是有关匿名通道的知识啦,我们之后博客会简绍另一个通道--命名通道哦,敬请期待!!

相关推荐
Championship.23.247 小时前
Linux 3.0 锁机制与故障排查详解
linux·运维·服务器
天疆说7 小时前
Zotero Connector 在 Edge 里找不到桌面 Zotero(Linux / Zotero 9.0.6 / Edge 150)
linux·前端·edge
风123456789~9 小时前
【Linux专栏】ls 排除某个文件
linux·运维·服务器
IT曙光10 小时前
ubuntu apt-get离线源制作
linux·ubuntu
其实防守也摸鱼10 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚10 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
玖玥拾11 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
土星云SaturnCloud11 小时前
边缘计算驱动绿氢生产过程智能寻优:电解槽级实时优化技术解析
服务器·人工智能·ai·边缘计算
Darkwanderor11 小时前
对Linux的进程控制的研究
linux·运维·c++
Web极客码12 小时前
突破并发瓶颈:云端高性能架构如何赋能海外 AI Agent 矩阵的高效产出
服务器·人工智能·架构