本文共 3546 字,大约阅读时间需要 11 分钟。
管道由创建,提供一个单路(单向)数据流
int pipe(int pipefd[2]); // int pipe2(int pipefd[2], int flags); // O_NONBLOCK、O_ASYNC, 设置O_ASYNC标志会导致新输入变为时生成的信号(默认为SIGIO) pipefd 为 pipe() 分配的两个文件描述符。 pipefd[0]:读文件描述符,内核对于管道的fd[0]描述符是以只读方式打开的。 pipefd[1]:写文件描述符,同理fd[1]是以只写方式打开的。
管道随进程:
单个进程内的管道,刚fork()
之后: 父进程关闭读端,子进程关闭写端后: 应用:shell 命令 双向通道: fd[1]和fd[0]都是可读写的,但是写入fd[1]的数据只能从fd[0]读取,反之亦然。数据流(数据通道)独立,不然很可能读取到自己写入的数据。 V节点
存放的是管道对象的指针)作为关于管道的一个实例,就是标准I/O函数库提供的popen()
,该函数创建一个管道,并fork一个子进程,该子进程根据popen()
传入的参数,关闭管道的对应端,然后执行传入的shell命令,然后等待终止。
调用进程和fork的子进程之间形成一个管道。调用进程和执行shell命令的子进程之间的管道通信是通过popen返回的FILE*来间接的实现的,调用进程通过标准文件I/O来写入或读取管道。
pclose()
会关闭由popen创建的标准I/O流,等待其中的命令终止,然后返回shell的执行状态。
char *cmd = "ls /usr/local/bin "; FILE *p = popen(cmd, "r"); char buf[256]; while (fgets(buf, sizeof(buf), p) != NULL) { printf("%s\n", buf); } pclose(p);
int mkfifo(const char *pathname, mode_t mode); open()
[root@idcserver program]# mkfifo skywalker[root@idcserver program]# echo "I have liked yuki..." >skywalker &[root@idcserver program]# cat < skywalkerI have liked yuki...[1]+ Done echo "I have liked yuki..." > skywalker
O_NONBLOCK
打开文件状态标志,可以实现非阻塞 I/O 。在阻塞的情况下:
在非阻塞的情况下:
系统内核对于管道和FIFO的唯一限制为:OPEN_MAX
和PIPE_BUF
;
OPEN_MAX
:一个进程在任意时刻可以打开的最大描述符数。
PIPE_BUF
: 标识一个管道可以原子写入管道和FIFO的最大字节数,并不是管道或FIFO的容量。 父子进程无名管道采用单工方式进行通信,只能一个写另外一个读。如果要实现双工,那么就创建两个无名管道来实现双工通信。
当无名管道相关联的所有文件描述符被关闭,那么无名管道对象会从内核中释放掉。
Q: 匿名管道可否用于不同进程?不同线程?如何用?A: 无名管道不单可以在父子进程中,也可用于不同的程序中。要实现A程序通过无名管道与B程序进行通信,那么可以在A程序中采用fork+exec模式启动B程序,同样可以把文件描述符复制到B程序中,这样就可以使用管道文件描述符进行通信了。
管道与FIFO的区别: 在于无名管道没有具体的文件,而有名管道在文件系统中有对应的文件(但是FIFO依然是随进程的,进程消失,管道内的内容失效)。
管道读取数据的四种的情况(O_NONBLOCK默认未设置):
(1)读端不读,写端一直写——写端不阻塞,直到写满管道才阻塞 (2)写端不写,但是读端一直读——读端阻塞 (3)读端一直读,且fd[0]保持打开,而写端写了一部分数据不写了,并且关闭fd[1]。——通道关闭的条件是所有的fd都关闭,所以此时通道未关闭,可以将通道内的消息继续读完。 (4)读端读了一部分数据,不读了且关闭fd[0],写端一直在写且f[1]还保持打开状态。——原理同上。可以继续写,直到通道写满。管道容量大小 : /proc/sys/fs/pipe-max-size
(以字节为单位)(1048576=1 MiB)
PIPE_BUF
:大于PIPE_BUF
字节的写入(见pipe(7))将被分割成多个数据包。
转载地址:http://oviti.baihongyu.com/