Linux进程间通信之管道

Linux进程间通信——管道通信详解 进程间通信:管道引言进程间通信管道 引言 进程是相互独立的,每个进程都有自己的虚拟地址空间,虚拟地址空间通过页表的映射,映射到自己的物理内存上,互不影响。正因为如此,进程间通信就变得很麻烦,操作系统为了使进程间能够通信,会提供一个介质,让多个进程都能够访问,也就是在内存上开辟一块公共资源,让进程在公共资源上交流。 进程间通信 在Linux系统中,有时候需要多个进程之间相互协作,共同完成某项任务,进程之间或线程之间有时候需要传递信息,有时候需要同步协调彼此工作,则就会出现进程间通信。 信号也是进程间通信的一种 阅读详情

IPC是进程间通信(interprocess communication)的简称。我们在这里对有关管道的知识进行总结。
我们将介绍三种` 管道:

  • 管道(pipe)。管道是第一个广泛使用的IPC形式,既可在程序中使用,也可以从shell中使用。管道只能在具有共同祖先(指父子进程关系)的进程间使用。
  • FIFO。FIFO是管道概念的一个变体,FIFO(First In First Out,先进先出),也叫有名管道。可以用于任意进程间通信。
  • socketpair。socket编程接口提供的一个创建全双工管道的系统调用。也被称为流管道。

管道:

管道只能用于具有相关关系的进程之间通信,所谓的相关关系,即拥有血缘关系的进程,具有共同祖先。
管道是一个字节流,意味着在使用管道时是不存在消息或消息边界的概念的。从管道中读取数据的进程可以读取任意大小的数据块,而不管写入进程写入管道的数据块的大小是什么。此外,通过管道传递的数据是顺序的—-从管道中读取出来的字节的顺序与它们被写入管道的顺序是完全一样的。
在管道中数据的传递方向是单向的。管道的一端用于写入,另一端则用于读取。
管道的容量是有限的。一旦管道被填满之后,后续向该管道的写入操作就会被阻塞直到读者从管道中移除了一些数据为止。

函数原型:
#include<unistd.h>

int pipe(int filedes[2]);


说明:

成功的pipe()调用会在数组filedes中返回两个打开的文件描述符:一个表示管道的读取端(filedes[0]),另一个表示管道的写入端(filedes[1])。
与所有文件描述符一样,可以使用read()和write()系统调用在管道上执行I/O。
管道是父进程和子进程间通信的常用手段。管道能在父,子进程间传递数据,利用的是fork调用之后两个管道文件描述符两个都保持打开。

使用pipe()创建完管道之后的情况,如图:
这里写图片描述

调用fork()之后,如图:
这里写图片描述

关闭未使用的文件描述符后:
这里写图片描述

虽然父进程和子进程都可以从管道中读取和写入数据,但这种做法并不常见。因此,在fork()调用之后,其中一个进程应该立即关闭管道的写入端的描述符,另一个则应该关闭读取端的描述符。比如,如上图所示,如果父进程需要向子进程传输数据,那么它就会关闭管道的读取端的描述符,而子进程就会关闭管道的写入端的描述符。

显然,如果要实现父,子进程之间的双向数据传输,就必须使用两个管道:创建两个管道,在两个进程之间发送数据的两个方向上各使用一个。

程序示例:

使用管道将数据从父进程传输到子进程。

int filedes[2];

if(pipe(filedes)==-1)   //创建管道
    errExit("pipe");

switch(fork()){    //创建子进程
case -1:
    errExit("fork");
case 0:   //child
    if(close(filedes[1])==-1)   //关闭子进程管道写端
        errExit("close");
    break;
default:    //parent
    if(close(filedes[0])==-1)  //关闭父进程管道读端
        errExit("close");
    break;
}


补充:

需要注意的是,当使用两个管道,实现父子进程双向通信时,要注意会发生死锁的情况。因为创建的管道描述符默认是阻塞的。如果两个进程都试图从空管道中读取数据或尝试向已满的管道中写入数据就可能会发生死锁。

关闭未使用的管道文件描述符不仅仅是为了确保进程不会耗尽其文件描述符的限制——-这对于正确使用管道是非常重要的。
当一个管道的所有的写入端都被关闭时,管道的读端调用recv时,recv会返回0,表示文件结束。
如果读取进程没有关闭管道的写入端,那么在其他进程关闭了写入描述符之后,读者也不会看到文件结束,即使它读完了管道中的所有数据,read()也会阻塞以等待数据,这是因为内核知道至少还存在一个管道的写入描述符打开着,即读取进程自己打开了这个描述符。
同理,如果写入进程没有关闭管道的读取端,那么即使在其他进程已经关闭了管道的读取端之后写入进程仍然能够向管道写入数据,最后写入进程会将数据充满整个管道,后续的写入请求会被永远阻塞。



FIFO:

管道没有名字,因此它们的最大劣势是只能用于有一个共同祖先进程的各个进程之间。
FIFO与管道类似,它们两者之间最大的差别在于FIFO在文件系统中拥有一个名称,并且其打开方式与打开一个普通文件是一样的。这样就能够将FIFO用于非相关进程之间的通信。它是一个单向(半双工)数据流。FIFO由mkfifo函数创建。

#include<sys/types.h>
#include<sys/stat.h>

int mkfifo(const char *pathname,mode_t mode);

成功则返回0,出错则返回-1。
其中pathname是路径名,它是该FIFO的名字。
mode参数指定文件权限位,类似于open的第二个参数。
mkfifo函数已隐含指定O_CREAT | O_EXCL。也就是说,它要么创建一个新的FIFO,要么返回一个EEXIST错误(如果所指定名字的FIFO已经存在)。如果不希望创建一个新的FIFO,那就改为调用open而不是mkfifo。
在创建出一个FIFO后,它必须或者打开来读,或者打开来写,所用的可以是open函数,也可以是某个标准I/O打开函数,例如fopen。FIFO不能打开来既读又写,因为它是半双工的。

FIFO与管道的例子变动如下:

  • 创建并打开一个管道只需要调用pipe。创建并打开一个FIFO则需在调用mkfifo之后再调用open。
  • 管道在所有进程最终都关闭它之后自动消失。FIFO的名字则只有通过调用unlink才从文件系统删除。


代码示例:

同pipe一样,FIFO是单向的。如果想要实现两个进程之间双向通信,则需要创建两个FIFO。其中的一个进程打开第一个FIFO来写,打开第二个FIFO来读。另一个进程打开第一个FIFO来读,打开第二个FIFO来写。下面的代码是父进程与子进程之间通过FIFO实现双向通信的代码示例,无血缘关系的进程之间同样可以使用FIFO进行通信,方法步骤都是一样的。


#define FIFO1   "/tmp/fifo.1"
#define FIFO2   "/tmp/fifo.2"
//允许用户读,用户写,组成员读和其他用户读
#define FILE_MODE  (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main()
{
    int readfd,writefd;
    pid_t childpid;
    if((mkfifo(FIFO1,FILE_MODE)<0)&&(errno!=EEXIST))
        err_sys("can't create %s ",FIFO1);
    if((mkfifo(FIFO2,FILE_MODE)<0)&&(errno!=EEXIST))
    {
        unlink(FIFO1);
        err_sys("can't create %s",FIFO2);
    }
    if((childpid = fork())==0)
    {
        readfd=open(FIFO1,O_RDONLY,0);
        writefd=open(FIFO2,O_WRONLY,0);
        //......
        exit(0);
    }
    writefd=open(FIFO1,O_WRONLY,0);
    readfd=open(FIFO2,O_RDONLY,0);
    //.....

    waitpid(childpid,NULL,0);
    close(readfd);
    close(writefd);

    unlink(FIFO1);
    unlink(FIFO2);
}


创建互联socket对:socketpair()

socket编程接口提供了一个创建全双工的管道的系统调用:socketpair。

#include<sys/socket.h>

int socketpair(int domain,int type,int protocol,int sockfd[2]);

socketpair()系统调用只能用在UNIX domain中,即domain参数必须被指定为AF_UNIX。protocol参数必须指定为0。
将type参数指定为SOCK_STREAM,创建一个双向管道(也被成为流管道)。
sockfd数组返回了引用这两个相互连接的socket的文件描述符。
每个socket都可以用来读取和写入,并且这两个socket之间每个方向上的数据信道是分开的。这对套接字可以进行双工通信,每一个描述符既可以读也可以写。这个在同一个进程中也可以进行通信,向sockfd[0]中写入,就可以从sockfd[1]中读取(只能从sockfd[1]中读取),也可以在sockfd[1]中写入,然后从sockfd[0]中读取;但是,若没有在0端写入,而从1端读取,则1端的读取操作会阻塞。
在Linux中,完全可以把这一对socket当成pipe返回的文件描述符一样使用,唯一的区别就是这一对文件描述符中的任何一个都可读和可写。


代码示例:

其实socketpair的使用和pipe的使用完全类似,只不过socketpair创建的是全双工的管道,是双向的。比如父子进程之间通信,调用socketpair创建一个全双工管道,然后调用fork()函数。子进程会拷贝这一对文件描述符。此时,我们可以规定让父进程使用sockfd[0]这个描述符,在父进程中关闭sockfd[1]这个描述符。在子进程中关闭sockfd[0]这个描述符。这样,不管读还是写,父进程只需要通过对sockf[0]这个文件描述符进行I/O操作,就可以完成。

/*************************************************************************
> File Name: 1.c
> Author:fengxin 
> Mail:903087053@qq.com 
> Created Time: 2017年07月29日 星期六 10时59分08秒
************************************************************************/

/*  
*进程双向通信  
*/  
#include<stdio.h>  
#include<string.h>  
#include<sys/types.h>  
#include<stdlib.h>  
#include<unistd.h>  
#include<sys/socket.h>  


int main()     
{  
    int sv[2];    //一对无名的套接字描述符  
    if(socketpair(PF_LOCAL,SOCK_STREAM,0,sv) < 0)   //成功返回零 失败返回-1  
    {  
        perror("socketpair");  
        return 0;  
    }  

    pid_t id = fork();        //fork出子进程  
    if(id == 0)               //子进程  
    {  

        close(sv[0]); //在子进程中关闭第一个描述符,使用第二个描述符  

        const char* msg = "我是孩子\n";  
        char buf[1024];  
        while(1)  
        {  
            write(sv[1],msg,strlen(msg));  
            sleep(1);  

            ssize_t _s = read(sv[1],buf,sizeof(buf)-1);  
            if(_s > 0)  
            {  
                buf[_s] = '\0';  
                printf(" %s\n",buf);  
            }  
        }  
    }  
    else   //父亲  
    {  
        close(sv[1]);//父进程关闭第二个描述符 ,使用第一个描述符
        const char* msg = "我是父亲\n";  
        char buf[1024];  
        while(1)  
        {  
            ssize_t _s = read(sv[0],buf,sizeof(buf)-1);  
            if(_s > 0)  
            {  
                buf[_s] = '\0';  
                printf(" %s\n",buf);  
                sleep(1);  
            }  
            write(sv[0],msg,strlen(msg));  
        }  
    }  
    return 0;  
}  
Linux进程间通信-管道 其实就是文件表的下标值。 阅读详情

相关推荐

别再乱调NvM_WriteBlock了!手把手教你搞懂Autosar NVM状态机与读写时序

本文深入解析Autosar NVM状态机与读写时序,帮助开发者避免常见错误。通过详细的状态机解读、最佳实践代码示例和异常处理策略,提升嵌入式系统中数据存储的可靠性。特别针对NvM_WriteBlock的调用逻辑和状态机机制进行实战讲解,解决工程师在实际开发中遇到的异步写入问题。

weixin_33701617的博客 344

基于多进程并发-进程通讯之管道(pipe)

匿名管道只能用于父子进程间通信 ,不能跨网络通信,并且通信是单向。另外,管道传输的数据是⽆格式的流且⼤⼩受限。正常情况下,控制台进程的输输入出是在控制台窗口的,但是如果我们在创建子进程的时候指定了其输入输出,那么子进程就会从我们的管道读数据,把输出数据写到我们指定的管道。这就是我们代码中重定向标准输入的原因,否则system(“pause”)会无效。命名管道,顾名思义,这个管道肯定是有名字的。通过管道的名字来确保多个进程访问同一个管道。

qq_43148810的博客 1778

Astah 9.0升级步骤(Widnows/Mac OS)

Astah Professional是一款全新的轻量级UML建模工具。软件集思维导图和UML建模于一体,采用100%纯JAVA构建, 兼容性强,不仅能够实现分布式建模、项目合并,还能够实现和其它建模工具的交互。

tequiero777的博客 2824

进程间通信

一、管道 管道的作用是在具有亲缘关系的进程之间传递消息,所以管道并不是只可以用于父子进程通信,也可以在兄弟进程之间还可以用在祖孙之间等,反正只要共同的祖先调用了pipe函数,打开的管道文件就会在fork之后,被各个后代所共享。不过由于管道是字节流通信,没有消息边界,多个进程同时发送的字节流混在一起,则无法分辨消息,所有管道一般用于2个进程之间通信,另外管道的内容读完后不会保存,管道是单...

草戍无心 228

SAP CO-PA获利分析避坑指南:从数据采集到报表设计的5个关键步骤

本文深入解析了SAP CO-PA获利分析模块从数据采集到报表设计的完整流程。文章重点剖析了数据源头、特征派生、获利段设计等关键步骤,并对比了基于账户与基于成本核算两种模式的差异,特别强调了在S/4HANA时代的选择与常见陷阱,旨在帮助企业构建可靠、可执行的盈利分析体系。

flink9streamer的博客 826

golang任意代码免杀绕过火绒+电脑管家

火绒和电脑管家主要以静态规则为主,但是有时候静态杀起来也挺让人奔溃的,这边分享一下如何拿捏火绒和电脑管家本文主要介绍如何通过garble进行混淆编译来绕过火绒,garble也可以绕过其他杀软,但是对火绒和电脑管家特别有效果,以火绒为例 下面来对比一下golang原生和garble混淆编译后得差距来一个很原始的的shellcode loader代码,将原始shellcode base64后就进行加载执行。

2301_79571829的博客 1533

Linux系统编程——进程间通信

消息队列通过名字字面意思理解就是队列排队结构,消息队列与FIFO很相似,都是一个队列结构,都可以有多个进程往队列里面写信息,多个进程从队列中读取信息。但FIFO需要读、写的两端事先都打开,才能够开始信息传递工作。而消息队列可以事先往队列中写信息,需要时再打开读取信息。

m0_67407774的博客 663

【Unity 实用工具篇】 | Book Page Curl 快速实现翻书效果

游戏和应用开发中,真实感的交互设计能显著提升用户体验。Unity3D图书翻页效果插件为开发者提供了一种便捷方式,可在项目中实现高度拟真的书籍翻页动画。 本文介绍该插件的快速使用方法,涵盖从基础导入到自动翻页效果创建的全过程,让我们快速实现翻页效果。

努力前行,总会成为自己心中的那道光 1万+

进程间的通讯--管道(有名、无名)

进程间的通讯–管道(有名、无名) 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。(无名管道) 【命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。】 管道 1、特点: 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。 它只能用于具有亲缘关系的进程之间的...

star_fighting的博客 997

Android 15.0 app进程保活白名单功能实现

在15.0的系统rom产品开发中,在某些重要的app即使进入后台,产品需求要求也不想被系统杀掉进程,需要app长时间保活,就是app进程保活白名单功能的实现, 所以需要在系统杀进程的时候不杀掉白名单的进程,接下来就看怎么样来实现这些功能

安卓兼职framework和app工程师的博客 638

消息平台接入实战:Hermes Agent 实现微信/钉钉日常任务自动化的 4 步配置

揭示 Hermes Agent 接入微信/钉钉时高频失效的根本原因——非 API 调用问题,而是上下文边界缺失;详解通过 soul.md 锁定人格基线、skills/ 目录原子化封装技能、CLAUDE.md 控制记忆节奏、Docker 环境适配四步构建可信赖自动化信任链,并给出身份证号过滤、中文标点

weixin_42520239的博客 162

文件描述符与进程间通信之关联

最近在想一个问题,关于进程间通信的问题,我们都知道进程间可以通过管道通信,但是为什么进程间可以通过管道通信呢?管道通信的机制又是什么呢?我想很多人应该没有去思考过,下面我来讲讲我对管道通信机制的理解。 如果两个不相关的进程打开同一个文件,一个只读方式开打,一个只写方式打开,不就相当于创建了一个管道了,进程A往里面写,进程B读,同样实现进程间通信。管道其实也一样。 一般的管道,只能在父子进程间进...

weixin_30507481的博客 184

我的PCB设计经验总结及最容易犯错的100例之二B07

本文总结了PCB设计中的常见错误及解决方法。作者通过记录自身及他人的设计失误,系统归纳了高频、隐蔽且致命的问题,如电容中间穿线、高速信号跨分割、锐角布线等。重点提出从错误中提炼规律,建立分类案例库,并开发自动化检查工具的方法。案例涵盖高速信号处理、电源设计、EMC防护等关键领域,强调通过原理理解和实践验证提升设计质量。文章建议工程师建立个人错误数据库,从被动纠错升级为主动预防,最终形成系统化的设计方法论,提高PCB一次成功率。

启芯硬件的博客 82

Linux 进程间通信(管道)

进程间通信、匿名管道、命名管道 ...

2201_75663820的博客 2733

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

【Linux】进程间通信之匿名管道

进程通信之匿名管道通信的概念和实现

s_little_monster的博客 8175

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Linux进程间通信之匿名管道

进程间通信介绍 1. 进程间通信的目的 2. 进程间通信发展 什么是管道 匿名管道 1. 什么是匿名管道 2. 匿名管道样例详解 3. 原理 4. 单个父进程与多个子进程管道间通信 建立子进程任务相关的头文件 主文件的建立 执行结果 5. 管道读写规则 6. 管道特点

立志做一个高产且细节博主 2145

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【Linux】进程间通信——命名管道

匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以使用命名管道来做这项工作。在Linux系统中,命名管道(也称为FIFO)是一种特殊的文件类型,它允许进程间进行通信。与匿名管道不同,命名管道存在于文件系统中,并且可以被任何有适当权限的进程访问。命名管道提供了一种方法,使得不相关的进程能够通过预先定义好的路径来交换数据。匿名管道由pipe函数创建并打开。而命名管道由mkfifo函数创建,打开⽤open。FIFO(命名管道)与pipe。

Renswc的博客 3324

Linux之进程间通信——管道

管道是Linux中最古老的进程间通信的方式,本文介绍了进程间通信的相关概念,主要介绍了匿名管道和命名管道。

一只小卷毛的博客 2801

Linux进程间通信【匿名管道】

进程间通信简称为IPC(Interprocess communication),是两个不同进程间进行任务协同的必要基础。进行通信时,首先需要确保不同进程之间构建联系,其次再根据不同的使用场景选择不同的通信解决方案,本文主要介绍的通信解决方案为匿名管道

北 海的博客 1万+

深入了解linux系统—— 进程间通信之管道

进程间通信与管道 进程间通信(IPC)是指在同一台计算机或不同计算机上的进程之间进行数据交换的技术。由于进程具有独立性,必须通过操作系统提供的共享资源实现通信。常见的IPC方式包括管道、共享内存、消息队列、信号/信号量以及套接字。 管道分为匿名管道和命名管道。匿名管道通过pipe()系统调用创建,适用于父子进程间的单向通信。其本质是一个由操作系统维护的无名文件,父子进程通过继承文件描述符访问同一资源。代码示例展示了子进程写入、父进程读取的通信过程,验证了管道的数据传输功能。 管道通信存在四种典型情况:单向读

LH__1314的博客 1626

Linux 进程间通信——管道

本篇博客主要介绍了Linux中进程间通信的一种基础方式——管道,包括匿名管道和命名管道的基本原理、特性及代码实现。匿名管道适用于父子进程间的单向通信,而命名管道则可以用于任何没有亲缘关系的进程间通信。理解管道的特性和使用方法,是掌握Linux进程间通信的关键步骤。

wxk2227814847的博客 1426

Linux进程间通信——使用命名管道

在前一篇文章——Linux进程间通信——使用匿名管道中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程之间交换数据带来了不方便。这里将会介绍进程的另一种通信方式——命名管道,来解决不相关进程间的通信问题。 一、什么是命名管道 命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系

ljianhui的专栏 8万+

Linux 进程间通信 管道系列: 匿名和命名管道,自定义shell当中命令行管道的模拟实现

Linux 进程间通信 管道系列: 匿名和命名管道,自定义shell当中命令行管道的模拟实现

Wzs040810的博客 2412

【Linux】进程间通信介绍 | 管道

本篇博客主要讲解了什么是进程间通信、进程间通信的目的、什么是管道、管道的原理、匿名管道、管道的特点、命名管道等等。

joy.728的博客 2329

Linux:进程间通信---匿名管道

进程间通信:两个或者多个进程实现数据层面的交互,因为进程独立性的存在,导致进程通信的成本比较高。本篇文章从进程间通信的定义出发,由浅入深,从理论到原理解析,从解析到实例分析,最后再到运用的场景,我们不仅知道了进程间通信的本质就是不同进程间看到同一份资源,还知道了管道的系统调用和管道的使用,通过总结四种情况和五中特征的方式了解深入了解了管道的使用情况!!!

知北游天的博客 5865
上一篇: c++通过cout输出字符变量的地址
下一篇: Linux进程间通信之POSIX消息队列
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值