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

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

1.什么是管道

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

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

2.匿名管道

1.原理

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

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

2.pipe函数

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

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

对于成功创建的管道,pipefd[2]应该保存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;
}

运行结果如下:

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

相关推荐
kaoa0007 小时前
Linux入门攻坚——62、memcached使用入门
linux·运维·memcached
AI_56788 小时前
Selenium+Python可通过 元素定位→操作模拟→断言验证 三步实现Web自动化测试
服务器·人工智能·python
model20058 小时前
alibaba linux3 系统盘清理
linux·运维·服务器
WG_178 小时前
Linux:动态库加载总结_进程间通信+进程池 + 进程IPC(27/28/29/30/31/32)
linux·运维·服务器
一只懒鱼a9 小时前
docker部署nacos (版本2.3.2)
运维·docker
小赵还有头发9 小时前
安装 RealSense SDK (驱动层)
linux
Root_Hacker10 小时前
include文件包含个人笔记及c底层调试
android·linux·服务器·c语言·笔记·安全·php
REDcker10 小时前
RESTful API设计规范详解
服务器·后端·接口·api·restful·博客·后端开发
微学AI11 小时前
内网穿透的应用-告别局域网束缚!MonkeyCode+cpolar 解锁 AI 编程新体验
linux·服务器·网络
sunnyday042611 小时前
基于Netty构建WebSocket服务器实战指南
服务器·spring boot·websocket·网络协议