管道(PIPE)
管道的创建和使用流程
管道本身是一种文件(linux 一切皆文件),由于其特殊性,它的创建函数被封装
pipe(int fd[2])
,不同于linux下普通文件的创建(create(path,mode)
)管道的数据传输,是单向的,从fd[1]—–>fd[0],所以,在fd[1]这个文件描述符端,执行写操作
write(fd[1],buff,strllen(buff)+1)
;相应的,在fd[0]端执行读操作read(fd[0],buff,100)
(100是buff定义时的长度)- 管道只用于父子进程间的通讯,子写父读,或父读子写
- 在执行读写操作之前,把管道另一端的文件关闭,即先执行
close()
再执行read()/write()
全双工管道
创建两个普通管道,但读写端是这样设定的:
- 一进程先读后才,另一进程必须先写后读
- 两进程都可先写后读,但不可同时先读后写,不然父子进程都同时阻塞
注意
子进程,在进程的一开始处,如果子进程调用
exec 族函数
执行另外一个程序时,子进程不再共享父进程的文件描述符,linux
提供dup(int oldfd)
将子进程的文件描述符重定位到stdin
(在执行该函数之前,为确保重定向标准输入即fd=0,得先执行close(0)
),执行的新程序,从标准输入读入父进程传递的数据read(stdin,buf,bufsize)
管道本身具有一个缓冲区,并且它的大小在
include/linux/limits.h
被宏定义尾PIPE_BUF.在执行write(fd[0]),buf,bufsize)
时:PIPE_BUF
POSIX.1-2001 says that write(2)s of less than PIPE_BUF bytes must be atomic: the output data is written to the pipe as a contiguous
sequence. Writes of more than PIPE_BUF bytes may be nonatomic: the kernel may interleave the data with data written by other processes. POSIX.1-2001 requires PIPE_BUF to be at least 512 bytes. (On Linux,PIPE_BUF is 4096 bytes.) The precise semantics depend on whether the file descriptor is nonblocking (O_NONBLOCK), whether there are multiple writers to the pipe, and on n, the number of bytes to be written:
总结起来:
-
O_NONBLOCK disabled, n <= PIPE_BUF,All n bytes are written atomically; write(2) may block if there is not room for n bytes to be written immediately
阻塞模式时且n < PIPE_BUF:写入具有原子性,如果没有足够的空间供n个字节全部写入,则阻塞直到有足够空间将n个字节全部写入管道
-
O_NONBLOCK enabled, n <= PIPE_BUF, If there is room to write n bytes to the pipe, then write(2) succeeds immediately, writing all n bytes; otherwise write(2) fails, with errno set to EAGAIN.
非阻塞模式时且n < PIPE_BUF:写入具有原子性,立即全部成功写入,否则一个都不写入,返回错误
-
O_NONBLOCK disabled, n > PIPE_BUF The write is nonatomic: the data given to write(2) may be interleaved with write(2)s by other process; the write(2) blocks until n bytes have been written.
阻塞模式时且n > PIPE_BUF:不具有原子性,可能中间有其他进程穿插写入,直到将n字节全部写入才返回,否则阻塞等待写入
-
O_NONBLOCK enabled, n > PIPE_BUF If the pipe is full, then write(2) fails, with errno set to EAGAIN. Otherwise, from 1 to n bytes may be written (i.e., a “partial write” may occur; the caller should check the return value from write(2) to see how many bytes were actually written), and these bytes may be interleaved with writes by other processes.
非阻塞模式时且N > PIPE_BUF:如果管道满的,则立即失败,一个都不写入,返回错误,如果不满,则返回写入的字节数为1~n,即部分写入,写入时可能有其他进程穿插写入
- 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
- 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。
命名管道(named pipe/FIFO)
为啥引入有名管道?
- 首先解决不相关进程间的通信问题;
- 其次FIFO是存在与磁盘上的文件(管道是在内存),这提供了一个路径名与之关联。进程只要知道该文件的路径,就能访问该文件,通过该文件进行通讯;
- 有名管道按先进先出的原则工作,第一个写入的数据首先被读出。
有名管道如何进行通讯
1.创建有名管道
#include <sys/types.h>
#include <sys/stat.h>
int mknode (const char* path,mode_t mode | S_IFIFO,(dev_t)0);
int mkfifo(const char *filename, mode_t mode);
mode 是读写权限
例如创建一个FIFO
...
#define deal_with_err(error_message) \
do{\
perror(error_message); \
exit(1); \
}while(0)
...
umask(0);
if(mkfifo("/tmp/fifo",S_IFIFO |0666)==-1)
{
deal_with_error("create FIOF fail");
}
// use mkfifo more frequently at your best
/*
if(mknod("/tmp/fifo",S_IFIFO | 0666,0) == -1)
{
deal_with_error("create FIOF fail");
}
*/
2.打开管道
open(const char *path, O_RDONLY);//1
open(const char *path, O_RDONLY | O_NONBLOCK);//2
open(const char *path, O_WRONLY);//3
open(const char *path, O_WRONLY | O_NONBLOCK);//4
3.读写操作
- 如果进行全双工通讯,注意
read()
,write()
顺序的安排