[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!)

这篇具有很好参考价值的文章主要介绍了[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        hello,大家好,本篇文章介绍Linux进程间的通信,包含内容有进程间通信的介绍、理解,管道的介绍使用:匿名管道,匿名管道的实现示例,匿名管道端口4种情况的探究。

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道  


 

目录

 1️⃣进程间通信 

🍙进程间通信目的

🍙进程间通信分类

🍙进程间通信的技术背景及必要性

🍙进程间通信的本质理解

2️⃣管道

🍙什么是管道

🍙匿名管道

🍥匿名管道原理

🍥匿名管道创建pipe

🍥匿名管道四种情况探究

🍥匿名管道读写规则

🍥匿名管道特定总结


1️⃣进程间通信 

🍙进程间通信目的

        ⭐ 数据传输:一个进程需要将它的数据发送给另一个进程
        ⭐ 资源共享:多个进程之间共享同样的资源。
        ⭐ 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如 进程终止时要通知父进程)。
        ⭐ 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

🍙进程间通信分类

🍘管道
  • 匿名管道pipe
  • 命名管道
🍘System V IPC
  • System V 消息队列
  • System V 共享内存
  • System V 信号量
🍘POSIX IPC
  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁

本篇文章只介绍管道和部分System V IPC

🍙进程间通信的技术背景及必要性

        进程具有独立性的。虚拟地址空间+页表 保证进程运行的独立性(进程内核数据结构+进程的代码和数据)

        通信成本会比较高!(因为进程独立性很强!)

🍣必要性:

        单进程无法使用进程间的并发能力!无法实现多进程之间的协同工作!所以需要进程间通信来使得多进程进行协同(进程间通信不是手段,是目的!)

🍙进程间通信的本质理解

进程间通信的本质:先让不同的进程看到同一份资源(内存空间)

        进程间通信的前提,首先需要让不同的进程看到同一块资源(特定的结构组织的)

        所以所谓的进程看到同一块资源,属于哪一个进程呢?不能隶属于任何一个进程,而应该更强调共享。

2️⃣管道

🍙什么是管道

  • 管道是Unix中最古老的进程间通信的形式
  • 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

生活中我们见过的管道有:水管、石油管道、天然气管道等等。

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道在Linux中也有管道,我们把这种将资源从一端送到另一端的数据流称为管道!!

特点:只能单向通信(半双工),传输的都是资源 -->数据!

🍙匿名管道

如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号“|"来使用管道,但是管理的真正定义是什么呢?管道是一个进程连接数据流到另一个进程的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入。

🌰在shell中输入命令:ls -l | grep my,我们知道ls命令(其实也是一个进程)会把当前目录中的文件都列出来,但是它不会直接输出,而是把本来要输出到屏幕上的数据通过管道输出到grep这个进程中,作为grep这个进程的输入,然后这个进程对输入的信息进行筛选,把存在my的信息的字符串(以行为单位)打印在屏幕上。

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道

🍥匿名管道原理

通过父子进程继承关系,再将文件描述符关闭,实现一端写,一端读,就是匿名管道。

        1.父进程以读写方式打开文件。父进程fork创建子进程,(进程具有独立性)子进程要拷贝一份PCB结构,PCB中包含了files_struct结构,files_struct中有一个指向struct file(文件)的指针数组,而文件描述符就是这个数组的下标。

        2.在拷贝后,子进程也就有了指向struct file(文件)的对应数组元素下标(文件描述符)。

        3.而struct file(文件)是独属于文件的,和进程没有关系,也就不用拷贝,也就是说此时父子进程公共区域就是 struct file。(实现不同进程看到同一份资源)

        4.write是系统调用接口,会将数据放在内核缓冲区,底层定期刷新缓冲区将内容写到磁盘。

        5.为了实现半双工的通信方式,一端读,一端写,关闭父子进程不需要的文件描述符。

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道
流程图

🍥匿名管道创建pipe

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道

int pipe(pipefd[2]);

参数:(输出型参数,通过参数找到打开的2个fd)文件描述符数组,其中pipefd[0]表示读端,pipefd[1]表示写端

返回值:成功返回0,失败返回错误码。

🍥匿名管道四种情况探究

🌰匿名管道实例:(子进程读取,父进程写入)

#include<iostream>
#include<unistd.h>
#include<assert.h>
#include<string>
#include<cstring>
#include<cstdio>
#include<sys/wait.h>
#include<sys/types.h>
using namespace std;

int main()
{
    //1.创建管道
    int pipefd[2]={0};//pipefd[0]:读端,pipefd[1]:写端
    int n=pipe(pipefd);
    assert(n!=-1);
    (void)n;//debug下assert有效,release下assert无效。只定义不使用n容易报警告

#ifdef DEBUG
    cout<<"pipefd[0]:"<<pipefd[0]<<endl;//3
    cout<<"pipefd[1]:"<<pipefd[1]<<endl;//4
#endif
    //2.创建子进程
    pid_t id=fork();
    assert(id!=-1);
    if(id==0)
    {
        //子进程
        //3.构建单向通信的信道,父进程写入,子进程读取
        //3.1关闭子进程不需要的fd
        close(pipefd[1]);
        char buffer[1024];
        while(true)
        {
            ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);
            if(s>0)
            {
                buffer[s]=0;//手动添加/0
                cout<<"我是子进程["<<getpid()<<"]Father#"<<buffer<<endl;   
            }
        }
        
        exit(0);
    }
    //父进程
    //3.构建单向通信的信道
    //3.1关闭父进程不需要的fd
    close(pipefd[0]);
    string message="我是父进程,我正在给你发消息";
    int count=0;
    char send_buffer[1024];
    while(true)
    {
        //3.2构建一个变化的字符串
        snprintf(send_buffer,sizeof(send_buffer),"%s[%d]:%d",message.c_str(),getpid(),count++);
        //3.3写入
        write(pipefd[1],send_buffer,strlen(send_buffer));
        //3.4故意sleep
        sleep(1);
    }
    pid_t res=waitpid(id,nullptr,0);
    assert(res>0);
    (void)res;
    close(pipefd[1]);
    return 0;
}
[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道
运行图

 A.写快,读慢,会发生什么?(我们修改代码,将子进程读端sleep(5),父进程添加一行打印send_buffer信息)

//添加父进程打印代码
//3.2构建一个变化的字符串      
snprintf(send_buffer,sizeof(send_buffer),"%s[%d]:%d",message.c_str(),getpid(),count++);
//3.3写入
write(pipefd[1],send_buffer,strlen(send_buffer));

printf("%s\n",send_buffer);
[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道
写快读慢结果图

我们可以看到一瞬间父进程写满了,然后阻塞等待子进程读取

B.写慢,读快,会发生什么?(父进程sleep(5),子进程不休眠)

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道
写慢结果图

我们可以看到,父进程在写入第一条信息后被子进程立刻读取,然后父进程休眠5s,子进程在这期间阻塞等待父进程继续写入 。

C.写端关闭,读端继续,会发生什么?(父进程关闭pipefd[1],即关闭写端,子进程修改代码显示read返回值不大于0的情况)

while(true)
        {
            ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);
            if(s>0)
            {
                buffer[s]=0;//手动添加/0
                cout<<"我是子进程["<<getpid()<<"]Father#"<<buffer<<endl;   
            }
            else 
            {
                cout<<s<<endl;
            }
            sleep(1);
        }
[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道
写端关闭结果图

结果显示:read返回0,read系统调用接口返回0即表示读取到文件结尾。

D.读端关闭,写端继续,会发生什么?(我们让子进程写数据,父进程读数据,读3次后关闭读端,此时父子进程读端都关闭)

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string>
#include <cstring>
#include <cassert>
int main()
{
    // 创建管道
    int pipefd[2] = {0};
    int n = pipe(pipefd);
    // 子进程继承
    pid_t id = fork();
    if (id == 0)
    {
        // 子进程写端
        close(pipefd[0]);
        std::string message = "我是子进程,我正在给你发消息";
        int count = 0;
        char send_buffer[1024];
        while (true)
        {
            if (count == 5)
                break;
            // 3.2构建一个变化的字符串
            snprintf(send_buffer, sizeof(send_buffer), "%s[%d]:%d", message.c_str(), getpid(), count++);
            // 3.3写入
            write(pipefd[1], send_buffer, strlen(send_buffer));
            sleep(1);
        }
        close(pipefd[1]);
        exit(0);
    }
    // 父进程读端
    close(pipefd[1]);
    char buffer[1024];
    for(int i=0;i<3;i++)
    {
        ssize_t s = read(pipefd[0], buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << "我是父进程:" << getpid() << "#" << buffer << std::endl;
        }
    }
    close(pipefd[0]);
    int status = 0;
    pid_t res = waitpid(id, &status, 0);
    assert(res > 0);
    (void)res;
    printf("接受到的信号为:%d\n", status & 0x7f);
    return 0;
}
[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道
读端关闭结果图

结果显示:父进程接受到子进程返回的13号信号(SIGPIPE,write进程发生中断)

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道
信号说明图

🍥匿名管道读写规则

         当没有数据可读时
                O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
                O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
         当管道满的时候
                O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
                O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
         如果所有管道写端对应的文件描述符被关闭,则read返回0
         如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出
         当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
         当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

🍥匿名管道特定总结

        ★管道是用来进行具有血缘关系的进程进行进程间通信——常用于父子通信

        ★管道具有通过让进程间协同,提供了访问控制!

        ★管道提供面向流式的通信的服务——面向字节流——一般需要协议

        ★管道是基于文件的,文件的生命周期是随进程的,管道的生命周期是随进程的!

        ★管道是单向通信的,就是半双工通信的一种特殊情况


        文末结语,本篇文章主要讲解进程间通信的目的、分类、技术背景必要性、以及对进程间通信的本质理解。并讲解管道之一的匿名管道,着重展现匿名管道的原理、创建,探究四种读写情况并最后进行总结。

        小伙伴们看到最后肯定会发现,匿名管道有一个很大的缺陷,就是必须要有父子关系的进程间进行通信,这是大大的限制了进程间的通信,那没有父子关系的进程如何通信呢?我们下一篇命名管道再讲解!

[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!),我在地球学Linux,linux,运维,服务器,进程间通信,匿名管道文章来源地址https://www.toymoban.com/news/detail-632473.html

到了这里,关于[Linux]进程间通信(上篇)——匿名管道(管道原理,实现示例,端口情况探究!!)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】进程间通信(匿名管道 & 命名管道)-- 详解

    如何理解进程间通信? 进程具有独立性,所以进程想要通信难度是比较大的,成本高。 在日常生活中,通信的本质是传递信息,但站在程序员角度来看, 进程间通信的本质:让不同的进程看到同一份资源(内存空间) 。 进程间通信就是进程之间互相传递数据,那么进程间

    2024年04月28日
    浏览(50)
  • Linux进程间通信【匿名管道】

    ✨个人主页: 北 海 🎉所属专栏: Linux学习之旅 🎃操作环境: CentOS 7.6 阿里云远程服务器 进程间通信简称为 IPC (Interprocess communication),是两个不同进程间进行任务协同的必要基础。进行通信时,首先需要确保不同进程之间构建联系,其次再根据不同的使用场景选择不同

    2024年02月08日
    浏览(78)
  • 【LInux】进程间通信 -- 匿名管道

    我们在学习进程管理,进程替换时,都强调了 进程的独立性 ,那进程间通信是什么?这好像和进程的独立性 相矛盾 吧? 那么今天,我们就来学习 进程间通信 ,和第一种通信方式 – 管道 进程间通信,并没有破坏进程的独立性这一特点,这点我们在 管道 讲解 而进程通信的

    2023年04月19日
    浏览(34)
  • Linux--进程间的通信-匿名管道

    进程间通信(IPC,Interprocess Communication)是指在不同进程之间传输数据和交换信息的一种机制。它允许多个进程在同一操作系统中同时运行,并实现彼此之间的协作 。 进程间通信方式: 管道(Pipe) : 管道是最基本的进程间通信方式 ,它是一种 半双工 的通信方式,通过管

    2024年04月14日
    浏览(42)
  • 【探索Linux】—— 强大的命令行工具 P.14(进程间通信 | 匿名管道 | |进程池 | pipe() 函数 | mkfifo() 函数)

    当今计算机系统中,进程间通信扮演着至关重要的角色。随着计算机系统的发展和复杂性的增加,多个进程之间的协作变得更加必要和常见。进程间通信使得不同进程能够共享资源、协调工作、传输数据,并实现更加复杂和强大的功能。本文将深入探讨进程间的通信,以及管

    2024年02月05日
    浏览(71)
  • 【Linux】匿名管道实现简单进程池

    管道内部没有数据且子进程不关闭自己的写端文件fd,读端(父进程)就要阻塞等待,直到管道里有数据。 管道内部被写满了且父进程(读端)不关闭自己的读端fd,写端(子进程)写满以后就要阻塞等待。 对于写端而言,如果写端不写了且关闭了写端fd,读端就会将管道中

    2024年04月22日
    浏览(34)
  • 【Linux】匿名管道与命名管道,进程池的简易实现

    本质是先让不同的进程看到同一份资源,也就是两个进程都能对管道文件的缓冲区进行操作 这里我们pipe的时候,会使用两个文件描述符,这两个文件描述里面存的file结构体是同一个,也就是管道文件的file结构体,file结构体中存储有inode以及系统缓冲区,此时fork一个子进程

    2024年02月05日
    浏览(42)
  • 进程间通信之匿名管道

    1.进程间为什么要进行通信? 进程间通信的是为了协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。 2.进程间通信的目的包括: 数据传输:一个进程需要将它的数据发送给另一个进程; 资源共享:多个进程间共享同样的资源; 通知事件:一个进程

    2024年02月16日
    浏览(41)
  • 【Linux从入门到精通】通信 | 管道通信(匿名管道 & 命名管道)

        本派你文章主要是对进程通信进行详解。主要内容是介绍 为什么通信、怎么进行通信。其中本篇文章主要讲解的是管道通信。希望本篇文章会对你有所帮助。 文章目录 一、进程通信简单介绍 1、1 什么是进程通信 1、2 为什么要进行通信  1、3 进程通信的方式 二、匿名管

    2024年02月09日
    浏览(46)
  • Linux系统编程:采用管道的方式实现进程间通信

    目录 一. 进程间通信概述 二. 管道的概念  三. 通过管道实现进程间通信 3.1 实现原理 3.2 匿名管道创建系统接口pipe 3.3 管道通信的模拟实现 3.4 管道通信的访问控制规则 3.5 管道通信的特点 四. 通过匿名管道实现进程池 4.1 进程池的概念 4.2 进程池的模拟实现 五. 命名

    2024年02月12日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包