Linux 进程间通信之管道(pipe),(fifo)
无名管道(pipe)
管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
定义函数: int pipe(int filedes[2])
filedes[0]为管道里的读取端
filedes[1]则为管道的写入端。
实现机制:
管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。

从原理上,管道利用fork机制建立,从而让两个进程可以连接到同一个PIPE上。最开始的时候,上面的两个箭头都连接在同一个进程Process 1上(连接在Process 1上的两个箭头)。当fork复制进程的时候,会将这两个连接也复制到新的进程(Process 2)。随后,每个进程关闭自己不需要的一个连接 (两个黑色的箭头被关闭; Process 1关闭从PIPE来的输入连接,Process 2关闭输出到PIPE的连接),这样,剩下的红色连接就构成了如上图的PIPE

一、管道读写注意点
1.必须在系统调用fork之前调用pipe,否则子进程不会继承文件描述符
2.只有在管道读端存在时,向管道写入才有意义;否则,会收到内核中的出错信号:SIFPIPE只有在管道读端存在时,向管道写入才有意义;否则,会收到内核中的出错信号:SIFPIPE
3.向管道写入数据时不保证写入的原子性,管道缓冲区一有空闲区域,写进程就试图向其写入内容。若读进程不读取管道中的内容,则写进程会一直阻塞。
4.父子进程在运行时,它们的先后顺序得不到保证。因此在这里,为保证父进程关闭读描述符,可向子进程加入sleep(2)。
二、实例
1.无名管道
/*pipe_rw.c*/
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h> int main()
{
int pipe_fd[];
pid_t pid;
char buf_r[];
char* p_wbuf;
int r_num;
memset(buf_r,,sizeof(buf_r));
if(pipe(pipe_fd)<)
{
printf("pipe create error\n");
return -;
}
if((pid=fork())==) //若是子进程
{
printf("\n");
/*关闭子进程管道写端。睡眠2秒,确保父进程已相应地关闭了管道读端*/
close(pipe_fd[]);
sleep();
/*子进程读取管道内容*/
if((r_num=read(pipe_fd[],buf_r,))>){
printf( "%d numbers read from the pipe is %s\n",r_num,buf_r);
}
/*关闭子进程读端*/
close(pipe_fd[]);
exit();
}
else if(pid>)
{ /*关闭父进程读端*/
close(pipe_fd[]);
/*分两次向管道写入数据*/
if(write(pipe_fd[],"Hello",)!=-)
printf("parent write1 success!\n");
if(write(pipe_fd[]," Pipe",)!=-)
printf("parent write2 success!\n");
/*关闭父进程写端并睡眠3秒,让子进程读数据*/
close(pipe_fd[]);
sleep();
/*收集子进程退出信息*/
waitpid(pid,NULL,);
exit();
}
}
运行结果如下:
[root@localhost ipc]# ./pipe_rw
parent write1 success!
parent write2 success!
numbers read from the pipe is Hello Pipe
2.命名管道(named PIPE)
由于基于fork机制,所以管道只能用于父进程和子进程之间,或者拥有相同祖先的两个子进程之间 (有亲缘关系的进程之间)。为了解决这一问题,Linux提供了FIFO方式连接进程。FIFO又叫做命名管道(named PIPE)。
FIFO (First in, First out)为一种特殊的文件类型,它在文件系统中有对应的路径。当一个进程以读(r)的方式打开该文件,而另一个进程以写(w)的方式打开该文件,那么内核就会在这两个进程之间建立管道,所以FIFO实际上也由内核管理,不与硬盘打交道。之所以叫FIFO,是因为管道本质上是一个先进先出的队列数据结构,最早放入的数据被最先读出来,从而保证信息交流的顺序。FIFO只是借用了文件系统(file system,命名管道是一种特殊类型的文件,因为Linux中所有事物都是文件,它在文件系统中以文件名的形式存在。)来为管道命名。写模式的进程向FIFO文件中写入,而读模式的进程从FIFO文件中读出。当删除FIFO文件时,管道连接也随之消失。FIFO的好处在于我们可以通过文件的路径来识别管道,从而让没有亲缘关系的进程之间建立连接
函数原型:
#include <sys/types.h>
#include <sys/stat.h> int mkfifo(const char *filename, mode_t mode);
int mknode(const char *filename, mode_t mode | S_IFIFO, (dev_t) );
其中pathname是被创建的文件名称,mode表示将在该文件上设置的权限位和将被创建的文件类型(在此情况下为S_IFIFO),dev是当创建设备特殊文件时使用的一个值。因此,对于先进先出文件它的值为0。
FIFO读写规则
1.从FIFO中读取数据: 约定:如果一个进程为了从FIFO中读取数据而阻塞打开了FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作
2.从FIFO中写入数据: 约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作。
一旦创建了了FIFO,就可open去打开它,可以使用open,read,close等去操作FIFO 当打开FIFO时,非阻塞标志(O_NONBLOCK)将会对读写产生如下影响:
1、没有使用O_NONBLOCK:访问要求无法满足时进程将阻塞。如试图读取空的FIFO,将导致进程阻塞;
2、使用O_NONBLOCK:访问要求无法满足时不阻塞,立即出错返回,errno是ENXIO;
/*fifo_write.c*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO_SERVER "/tmp/myfifo" main(int argc,char** argv)
{
int fd;
char w_buf[];
int nwrite; if(fd==-)
if(errno==ENXIO)
printf("open error; no reading process\n");
/*打开有名管道,并设置为非阻塞*/
fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,);
if(argc==)
printf("Please send something\n");
strcpy(w_buf,argv[]);
/*向管道写入字符串*/
if((nwrite=write(fd,w_buf,))==-)
{
if(errno==EAGAIN)
printf("The FIFO has not been read yet.Please try later\n");
}
else
printf("write %s to the FIFO\n",w_buf);
} /*fifo_read.c*/ #include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo" main(int argc,char** argv)
{
char buf_r[];
int fd;
int nread; /*创建有名管道,并设置相应的权限*/
if((mkfifo(FIFO,O_CREAT|O_EXCL)<)&&(errno!=EEXIST))
printf("cannot create fifoserver\n");
printf("Preparing for reading bytes...\n"); memset(buf_r,,sizeof(buf_r));
/*打开有名管道,并设置非阻塞标志*/
fd=open(FIFO,O_RDONLY|O_NONBLOCK,);
if(fd==-)
{
perror("open");
exit();
}
while()
{
memset(buf_r,,sizeof(buf_r));
/*读取管道中的字符串*/
if((nread=read(fd,buf_r,))==-){
if(errno==EAGAIN)
printf("no data yet\n");
}
printf("read %s from FIFO\n",buf_r);
sleep();
}
pause();
unlink(FIFO);//这个谁mkfifo创建谁释放
}
运行结果:
终端1:
[root@localhost ipc]# ./fifo_write
write to the FIFO
终端2:
[root@localhost ipc]# ./fifo_read
Preparing for reading bytes...
read from FIFO
read from FIFO
read from FIFO
read from FIFO
read from FIFO
read from FIFO
read from FIFO
总结:
1.read没有数据read阻塞,read读取后数据被删除
2.数据有序,安装写入的顺序
3.打开的描述符号可以读写(two-way)
4.管道文件关闭后,数据不持久
5.管道的数据在内核缓冲
6.有名管道的名字仅仅是内核识别是否放回同一个fd的标识
Linux 进程间通信之管道(pipe),(fifo)的更多相关文章
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道 ...
- linux进程间通信-有名管道(FIFO)
有名管道(FIFO) 命名管道也被称为FIFO文件,是一种特殊的文件.由于linux所有的事物都可以被视为文件,所以对命名管道的使用也就变得与文件操作非常统一. (1)创建命名管道 用如下两个函数中的 ...
- Linux 进程间通信 有名管道(fifo)
有名管道特点: 1)无名管道只能用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围 2)有名管道可以使互不相关的两个进程互相通信. 3)有名管道可以通过路径名来指出,并且在文件系统中可见,但内容 ...
- 进程间通信之管道--pipe和fifo使用
匿名管道pipe 函数原型: #include <unistd.h> int pipe(int fildes[2]); 参数说明 fildes是我们传入的数组,也是一个传出参数.filde ...
- Linux 进程间通信(二) 管道
Linux 进程间通信-管道 进程是一个独立的资源分配单位,不同进程之间的资源是相互独立的,没有关联,不能在一个进程中直接访问另一个进程中的资源.但是,进程不是孤立的,不同的进程之间需要信息的交换以及 ...
- Linux进程间通信(一) - 管道
管道(pipe) 普通的Linux shell都允许重定向,而重定向使用的就是管道. 例如:ps | grep vsftpd .管道是单向的.先进先出的.无结构的.固定大小的字节流,它把一个进程的标准 ...
- Linux -- 进程间通信之管道
管道是 Linux 里的一种文件类型,同时也是 Linux 系统下进程间通信的一种方式 创建一个管道文件有两种方式: Shell 下命令 mkfifo + filename,即创建一个有名管道 ...
- Linux学习笔记——管道PIPE
管道:当从一个进程连接数据流到另一个进程时,使用术语管道(pipe).# include <unistd.h> int pipe(int filedes[2]); //创建管道 pipe( ...
- Linux进程间通信-命名管道
前面我们讲了进程间通信的一种方式,匿名管道.我们知道,匿名管道只能用于父子关系的进程之间.那么没有这种关系的进程之间该如何进行数据传递呢? 1.什么是命名管道 匿名管道是在缓存中开辟的输出和输入文件流 ...
随机推荐
- scala中的注解
scala中很多注解实现java中关键字的用法 @volatile注解标记为易失的:@transient注解将字段标记为瞬态的:@strictfp注解对应strictfp修饰符:@native注解标记 ...
- Netty中的Future
先看下Future的整个继承体系,还有一个ChannelFuture不在里面: 在并发编程中,我们通常会用到一组非阻塞的模型:Promise,Future 和 Callback.其中的 Fut ...
- 操作系统--UNIX代码段和数据段分开
(1)代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像.代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作----它是不可写的. (2) ...
- 《Maven实战》笔记-7-持续集成
一.持续集成的步骤: 1.持续编译 2.持续数据库集成 3.持续测试 4.持续审查 5.持续部署 6.持续反馈 二.持续集成工具——Hudson 1.安装Hudson 2.准备Subversion ...
- MVC Areas
ASP.NET MVC中,是依靠某些文件夹以及类的固定命名规则去组织model实体层,views视图层和控制层的.如果是大规模的应用程序,经常会由不同功能的模块组成,而每个功能模块都由MVC中的三层所 ...
- Docker+Jenkins+Gogs 自动构建.Net Core
Docker+Jenkins+Gogs 自动构建.Net Core 引言 jenkins+gags 全部采用Docker安装,通过jenkins插件ssh调用外部Docker构建 主要实现功能: gi ...
- 在类中使用Response.Redirect()方法
问题来自:"我在app_code 定义了user.cs类:其中作了跳转:Httpcontect.Current.Response.Redirect("/c/index.aspx&q ...
- numpy中argsort函数用法
在Python中使用help帮助 >>> import numpy >>> help(numpy.argsort) Help on function argsort ...
- 从理论认识J2EE
前言 在学习J2EE这块,看了成套的视频,感觉,感觉,感觉收获不是特别大,没用马老师讲得好,但是多少还是和J2EE打了个招呼,比如J2EE著名的十三个规范,他们有的人说不算什么规范,顶多可以理解为十三 ...
- BS总结篇
学习Web开发差不多三个月了,这个阶段的学习给自己带来的更多的是视觉的盛宴.从CS的世界一下子来到了BS的地盘,心中除了惊喜还是惊喜.在这里还是希望自己对这三月所学的东西做一个阶段性的总结. 话不多说 ...