父进程 子进程 fd1[1] fd2[0] fd1[0] fd2[1] 进程 内核 管道1 数据流 管道2 数据流 图3:提供一个双向数据流的两个管道 管道读写分别使用read和write系统调用,其中读取字节数不应大于PIPE_BUF(
2.1 $command1 | command2
将command1的标准输出作为command2的标准输入。
mknod 创建块、字符或管道文件 mkfifo 创建一个命名管道(FIFO)
4. 系统调用
4.1 pipe(建立管道)
表头文件 #include
函数说明 pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。
返回值 若成功则返回零,否则返回-1,错误原因存于errno中。 错误代码 EMFILE 进程已用完文件描述词最大量。
ENFILE 系统已无文件描述词可用。 EFAULT 参数filedes数组地址不合法。
4.2 mkfifo(建立具名管道)
表头文件 #include
定义函数 int mkfifo(const char * pathname,mode_t mode);
函数说明 mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode&~umask),因此umask值也会影响到FIFO文件的权限。mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开FIFO文件时,O_NONBLOCK旗标会有影响
1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。 2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
返回值 若成功则返回0,否则返回-1,错误原因存于errno中。 错误代码 EACCESS 参数pathname所指定的目录路径无可执行的权限 EEXIST 参数pathname所指定的文件已存在。 ENAMETOOLONG 参数pathname的路径名称太长。 ENOENT 参数pathname包含的目录不存在 ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。 EROFS 参数pathname指定的文件存在于只读文件系统内。 4.3 open(打开文件)
表头文件 #include
定义函数 int open( const char * pathname, int flags); int open( const char * pathname,int flags, mode_t mode);
函数说明 参数pathname 指向欲打开的文件路径字符串。下列是参数flags 所能使用的旗标:
O_RDONLY 以只读方式打开文件 O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件。上述三种旗标是互斥的,也就是不可同时使用,但可与下列的旗标利用OR(|)运算符组合。
O_CREAT 若欲打开的文件不存在则自动建立该文件。
O_EXCL 如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。
返回值 若所有欲核查的权限都通过了检查则返回0 值,表示成功,只要有一个权限被禁止则返回-1。
错误代码 EEXIST 参数pathname 所指的文件已存在,却使用了O_CREAT和O_EXCL旗标。
EACCESS 参数pathname所指的文件不符合所要求测试的权限。 EROFS 欲测试写入权限的文件存在于只读文件系统内。 EFAULT 参数pathname指针超出可存取内存空间。 EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。 ENOTDIR 参数pathname不是目录。 ENOMEM 核心内存不足。
ELOOP 参数pathname有过多符号连接问题。 EIO I/O 存取错误。 4.4 close(关闭文件)
表头文件 #include
函数说明 当使用完文件后若已不再需要则可使用close()关闭该文件,二close()会让数据写回磁盘,并释放该文件所占用的资源。参数fd为先前由open()或creat()所返回的文件描述词。
返回值 若文件顺利关闭则返回0,发生错误时返回-1。
错误代码 EBADF 参数fd 非有效的文件描述词或该文件已关闭。 4.5 read(由已打开的文件读取数据)
表头文件 #include
定义函数 ssize_t read(int fd,void * buf ,size_t count);
函数说明 read()会把参数fd 所指的文件传送count个字节到buf指针所指的内存中。若参数count为0,则read()不会有作用并返回0。返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节
移动。
错误代码 EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。
EBADF 参数fd 非有效的文件描述词,或该文件已关闭。
4.6 write(将数据写入已打开的文件内)
表头文件 #include
定义函数 ssize_t write (int fd,const void * buf,size_t count);
函数说明 write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。当然,文件读写位置也会随之移动。
返回值 如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
错误代码 EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。
EADF 参数fd非有效的文件描述词,或该文件已关闭。
4.7 unlink(删除文件)
表头文件 #include
定义函数 int unlink(const char * pathname);
函数说明 unlink()会删除参数pathname指定的文件。如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。如果参数pathname为一符号连接,则此连接会被删除。 返回值 成功则返回0,失败返回-1,错误原因存于errno 错误代码 EROFS 文件存在于只读文件系统内 EFAULT 参数pathname指针超出可存取内存空间 ENAMETOOLONG 参数pathname太长 ENOMEM 核心内存不足
ELOOP 参数pathname 有过多符号连接问题 EIO I/O 存取错误 5. 标准库函数
5.1 popen(建立管道I/O)
表头文件 #include
定义函数 FILE * popen( const char * command,const char * type);
函数说明 popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()以外。 返回值 若成功则返回文件指针,否则返回NULL,错误原因存于errno中。 错误代码 EINVAL参数type不合法。 5.2 pclose(关闭管道I/O)
表头文件 #include
函数说明 pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的文件指针。
返回值 返回子进程的结束状态。如果有错误则返回-1,错误原因存于errno中。 错误代码 ECHILD pclose()无法取得子进程的结束状态。
实验要求:
1. 阅读以下程序:
#include
int filedes[2]; char buffer[80]; if(pipe(filedes)<0)
err_quit(―pipe error‖); if(fork()>0){