进程间通信之管道

简介:       管道是linux的一种通信方式,一种两个进程间进行单向通信的机制,它提供了简单的流控制机制,系统提供了pipe生成一个管道并返回两个描述符,一 个用来读管道,一个用来写管道,因此它们可以共享访问文件,这样每个管道就可以有很多个读进程和写进程,然而实际上进程不知道它正在读或写的是一个管道...

  

   管道是linux的一种通信方式,一种两个进程间进行单向通信的机制,它提供了简单的流控制机制,系统提供了pipe生成一个管道并返回两个描述符,一 个用来读管道,一个用来写管道,因此它们可以共享访问文件,这样每个管道就可以有很多个读进程和写进程,然而实际上进程不知道它正在读或写的是一个管道, 它有以下局限性:

  由于管道传递数据的单向性,决定其使用的局限性:数据的单向流动;有亲缘关系的进程间的通信;没有名字;缓冲区大小受限制(传送的是无格式的字节流)

     管道就是一个存在于内存的特殊文件,进程就是通过读写该文件进行通信的(内存中的某个页面作为数据缓冲区)

     如果要建立两个进程的数据通路,首先父进程应调用pipe创建管道,接着调用fork,由于子进程自动继承父进程的数据段,便可实现父子进程同时拥有管 道 的操作权,如下图(a),但为了维护管道,比如想要一个父进程到子进程的数据通道时,在父进程中关闭读出端,子进程中关闭管道的写入端,图(b)。

管道的创建
    Linux下创建管道可以通过函数pipe来完成。该函数如果调用成功返回0,并且数组中将包含两个新的文件描述符:如果有错误发生,返回-1。该函数原型如下:
#include <unistd.h>
int pipe(int fd[2]);
    管道两端可分别用描述符fd[0]以及fd[1]来描述。需要注意的是,管道两端的任务是固定的,一端只能用于读,由描述符fd[0]表示,称其为管道读 端;另一端只能用于写,由描述符fd[1]来表示,称其为管道写端。如果试图从管道写端读数据,或者向管道读端写数据都将导致出错。
    管道是一种文件,因此对文件操作的I/O函数都可以用于管道,如read(),write()等。
    注意:管道是一旦创建成功,就可以作为一般的文件来使用,对一般文件进行操作的I/O函数也适用于管道,如:
    管道的一般用法是,进程在使用fork函数创建子进程前先创建一个管道,该管道用于在父子进程间通信,然后创建子进程,之后你进程关闭管道的读端,子进程 关闭管道的写端。父进程负责向管道写数据而子进程负责读数据。当然父进程可以关闭管道的写端而子进程关闭管道的读端。这样管道就可以用于父子进程间的通 信,也可用于兄弟进程间的通信。下面介绍进程是如何通过管道来读写数据的。

管道关闭

        管道关闭只需将这两个文件描述符关闭即可,可以使用普通的close函数进行关闭。


从管道中读数据
    如果某进程要读取管道中的数据,那么该进程应当关闭fd1,同时向管道写数据的进程应当关闭fd0。因为管道只能用于具有亲缘关系的进程间的通信,在各进程进行通信时,它们共享文件描述符。在使用前,应及时地关闭不需要的管道的另一端,以避免意外错误的发生。
    进程在管道的读端读数据时,如果管道的写端不存在,则读进程认为已经读到了数据的末尾,该函数返回读出的字节数为0;管道的写端不存在,则读取的字节数大 于PIPE_BUF,则返回管道中现有的所有数据;如果请求的字节数不大于PIPE_BUF,则返回管道中现有的所有数据(此时,管道中数据量小于请求的 数据量),或者返回请求的字节数(此时,管道中数据量大于等于请求的数据量)。
    注意:PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。


向管道中写数据
    如果某进程希望向管道中写入数据,那么该进程应该关闭fd0文件描述符,同时管道另一端的进程关闭fd1。向管道中写入数据时,Linux不保证写入的原 子性(原子性是指操作在任何时候都不能被任何原因所打断,操作要么不做要么就一定完成)。管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读 进程不读走管道缓冲区中的数据,那么写操作将一直被阻塞等待。
    在写管道时,如果要求写的字节数小于等于PIPE_BUF,则多个进程对同一管道的写操作不会交错进行。但是,如果有多个进程同时写一个管道,而且某些进程要求写的字节数超过PIPE_BUF所能容纳时,则多个写操作的数据可能会交错。
    注意:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIGPIPE信号。应用程序可以处理也可以忽略该信号,如果忽略该信号或者捕捉该信号并从其处理程序返回,则write出错,错误码为EPIPE。

相关文章
|
1月前
|
存储 Unix Linux
进程间通信方式-----管道通信
【10月更文挑战第29天】管道通信是一种重要的进程间通信机制,它为进程间的数据传输和同步提供了一种简单有效的方法。通过合理地使用管道通信,可以实现不同进程之间的协作,提高系统的整体性能和效率。
|
7月前
|
存储 负载均衡 Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
|
7月前
|
消息中间件 Unix Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
|
7月前
|
Shell
【进程通信】利用管道创建进程池(结合代码)
【进程通信】利用管道创建进程池(结合代码)
|
3月前
|
消息中间件 Unix Linux
C语言 多进程编程(二)管道
本文详细介绍了Linux下的进程间通信(IPC),重点讨论了管道通信机制。首先,文章概述了进程间通信的基本概念及重要性,并列举了几种常见的IPC方式。接着深入探讨了管道通信,包括无名管道(匿名管道)和有名管道(命名管道)。无名管道主要用于父子进程间的单向通信,有名管道则可用于任意进程间的通信。文中提供了丰富的示例代码,展示了如何使用`pipe()`和`mkfifo()`函数创建管道,并通过实例演示了如何利用管道进行进程间的消息传递。此外,还分析了管道的特点、优缺点以及如何通过`errno`判断管道是否存在,帮助读者更好地理解和应用管道通信技术。
|
3月前
|
SQL 网络协议 数据库连接
已解决:连接SqlServer出现 provider: Shared Memory Provider, error: 0 - 管道的另一端上无任何进程【C#连接SqlServer踩坑记录】
本文介绍了解决连接SqlServer时出现“provider: Shared Memory Provider, error: 0 - 管道的另一端上无任何进程”错误的步骤,包括更改服务器验证模式、修改sa用户设置、启用TCP/IP协议,以及检查数据库连接语句中的实例名是否正确。此外,还解释了实例名mssqlserver和sqlserver之间的区别,包括它们在默认设置、功能和用途上的差异。
|
4月前
|
消息中间件 Linux 开发者
Linux进程间通信秘籍:管道、消息队列、信号量,一文让你彻底解锁!
【8月更文挑战第25天】本文概述了Linux系统中常用的五种进程间通信(IPC)模式:管道、消息队列、信号量、共享内存与套接字。通过示例代码展示了每种模式的应用场景。了解这些IPC机制及其特点有助于开发者根据具体需求选择合适的通信方式,促进多进程间的高效协作。
184 3
|
4月前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
74 0
|
4月前
|
Python
Python IPC深度探索:解锁跨进程通信的无限可能,以管道与队列为翼,让你的应用跨越边界,无缝协作,震撼登场
【8月更文挑战第3天】Python IPC大揭秘:解锁进程间通信新姿势,让你的应用无界连接
28 0
|
4月前
|
消息中间件 存储 网络协议
从零开始掌握进程间通信:管道、信号、消息队列、共享内存大揭秘
在操作系统中,进程间通信(IPC)是至关重要的,它提供了多种机制来实现不同进程间的数据交换和同步。本篇文章将详细介绍几种常见的IPC方式,包括管道、信号、消息队列、共享内存、信号量和套接字,帮助你深入理解并合理应用这些通信方式,提高系统性能与可靠性。
420 0

相关实验场景

更多