Linux下进程间通信 之 管道

  • 管道分为 “无名管道(pipe)” 和 “命名管道(fifo)”

        无名管道实际是用于进程间通信的一段共享内存,创建无名管道的进程称为“管道服务器”,连

接到无名管道的进程为“管道客户机”。一个进程在向无名管道写入数据后,另一进程就可以从无

名管道的另一端将其读取出来。

无名管道的特点:

        1、半双工,数据只能向一个方向流动;需要双方通信时,需要建立起两个无名管道。

        2、 只能用于父子进程或者兄弟进程之间( 具有亲缘关系的进程): 比如fork或exec创建的

               新进程(在使用exec创建新进程时,需要将管道的文件描述符作为参数传递给exec创建

               的新进程)。 当父进程与使用fork创建的子进程直接通信时,发送数据的进程关闭读

               端,接受数据的进程关闭写端。

        3、单独构成一种独立的文件系统:管道对于管道两端的进程而言就是一个文件,但它不是普

              通文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与

              内存中

        4、数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每

              次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

无名管道的实现机制:

        无名管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接

一个进程的输出,这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取

出被放入管道的信息。

        一个缓冲区不需要很大,它被设计成为环形数据缓冲区,以便管道可以被循环利用。当管道

中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息当管道被放满信息的

时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道

也自动消失。

        管道只能在本地计算机中使用,而不可用于网络间的通信。 

pipe函数原型:

#include <unistd.h> 
int pipe(int file_descriptor[2]);//建立管道,该函数在数组上填上两个新的文件描述符后返回0,失败返回-1。
eg.int fd[2]
int result = pipe(fd);

        通过使用系统调用read和write来访问数据。 向 file_descriptor[1]写 数据,从 file_descriptor[0]

中读数据。写入与读取的顺序原则是 先进先出。 

管道读写规则:

        当没有数据可读时

                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

        当要写入的数据量不大于PIPE_BUF(Posix.1要求PIPE_BUF至少 512字节)时,linux将保

        证写入的原子性。

        当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

名管道的特点:

        命名管道是一种特殊类型的文件,它在系统中以文件形式存在。这样克服了管道的弊端,可

以允许没有亲缘关系的进程间通信。 

        创建管道的两个系统调用原型:

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

int mkfifo(const char *filename,mode_t mode); 
//建立一个名字为filename的命名管道,参数mode为该文件的权限(mode%~umask),若成功则返回0,否则返回-1,错误原因存于errno中。

例如:mkfifo( "/tmp/cmd_pipe", S_IFIFO | 0666 );

        具体操作方法只要创建了一个命名管道然后就可以使用open、read、write等系统调用来操

作,创建可以手工创建或者程序中创建。 

int mknod(const char *path, mode_t mode, dev_t dev); 

//第一个参数表示你要创建的文件的名称,第二个参数表示文件类型,第三个参数表示该文件对应的设备文件的设备号。只有当文件类型为 S_IFCHR 或 S_IFBLK 的时候该文件才有设备号,创建普通文件时传入0即可。

例如:mknod(FIFO_FILE,S_IFIFO|0666,0);  

管道和命名管道的区别:

        对于命名管道FIFO来说,IO操作和普通管道IO操作基本一样,但是两者有一个主要的区别,

在命名管道中,管道可以是事先已经创建好的,比如我们在命令行下执行:mkfifo myfifo

就是创建一个命名通道,我们必须用open函数来显示地建立连接到管道的通道。而在无名管道

中,管道已经在主进程里创建好了,然后在fork时直接复制相关数据或者是用exec创建的新进程时

把管道的文件描述符当参数传递进去。

        一般来说FIFO和PIPE一样总是处于阻塞状态。也就是说如果命名管道FIFO打开时设置了读权

限,则读进程将一直阻塞,一直到其他进程打开该FIFO并向管道写入数据。这个阻塞动作反过来

也是成立的。如果不希望命名管道操作的时候发生阻塞,可以在open的时候使用O_NONBLOCK

标志,以关闭默认的阻塞操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值