管道通信
普通的Linux shell都允许重定向,而重定向使用的就是管道。例如:
ps | grep vsftpd
.管道是单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进
程在管道的道端读出数据。数据读出后将从管道中移走,其它读进程都不能再读到这些数据。管道提供了简单的流控制机制。进程试图读空管道时,在有数据写入管
道前,进程将一直阻塞。同样,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。管道主要用于不同进程间通信。
管道创建与关闭
创建一个简单的管道,可以使用系统调用pipe()。它接受一个参数,也就是一个包括两个整数的数组。如果系统调用成功,此数组将包括管道使用的两个文件描述符。创建一个管道之后,一般情况下进程将产生一个新的进程。
============================================================
系统调用:pipe();
原型:int pipe(int fd[2]);
返回值:如果系统调用成功,返回0。如果系统调用失败返回-1:
errno=EMFILE(没有空清的文件描述符)
EMFILE(系统文件表已满)
EFAULT(fd数组无效)
注意:fd[0]用于读取管道,fd[1]用于写入管道。
============================================================管道的创建- #include<unistd.h>
- #include<stdio.h>
- #include<stdlib.h>
- int main(int argc, char *argv[])
- {
- int pipe_fd[2];
- if (pipe(pipe_fd) < 0) {
- printf("pipe create error\n");
- return -1;
- } else
- printf("pipe create success\n");
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- }
管道的读写
管道主要用于不同进程间通信。实际上,通常先创建一个管道,再通过fork函数创建一个子进程。
子进程写入和父进程读
管道读写注意事项:
可以通过打开两个管道来创建一个双向的管道。但需要在子理程中正确地设置文件描述符。必须在系统调用fork()中调用pipe(),否则子进程将不会继承文件描述符。当使用半双工管道时,任何关联的进程都必须共享一个相关的祖先进程。因为管道存在于系统内核之中,所以任何不在创建管道的进程的祖先进程之中
的进程都将无法寻址它。而在命名管道中却不是这样。
管道实例:pipe_rw.c- #include<unistd.h>
- #include<stdio.h>
- #include<stdlib.h>
- int main(int argc char *argv[])
- {
- int pipe_fd[2];
- pid_t pid;
- char buf_r[100];
- char *p_wbuf;
- int r_num;
- memset(buf_r, 0, sizeof(buf_r));/*数组中的数据清0*/
- if (pipe(pipe_fd) < 0) {
- printf("pipe create error\n");
- exit(1);
- }
- if ((pid = fork()) == 0) {
- printf("\n");
- close(pipe_fd[1]);
- sleep(2);
- if ((r_num = read(pipe_fd[0], buf_r, 100)) > 0) {
- printf("%d numbers read from be pipe is %s\n",
- r_num, buf_r);
- }
- close(pipe_fd[0]);
- exit(0);
- } else if (pid > 0) {
- close(pipe_fd[0]);
- if (write(pipe_fd[1], "Hello", 5) != -1)
- printf("parent write success!\n");
- if (write(pipe_fd[1], " Pipe", 5) != -1)
- printf("parent wirte2 succes!\n");
- close(pipe_fd[1]);
- sleep(3);
- waitpid(pid, NULL, 0);
- exit(0);
- }
- exit(0);
- }
标准流管道
与linux中文件操作有文件流的标准I/O一样,管道的操作也支持基于文件流的模式。接口函数如下:
================================================================================
库函数:popen();
原型:FILE *open (char *command, char *type);
返回值:如果成功,返回一个新的文件流。如果无法创建进程或者管道,返回NULL。管道中数据流的方向是由第二个参数type控制的。此参数可以是r或者w,分别代表读或写。但不能同时为读和写。在Linux 系统下,管道将会以参数type中第一个字符代表的方式打开。所以,如果你在参数type中写入rw,管道将会以读的方式打开。
================================================================================使用popen()创建的管道必须使用pclose()关闭。其实,popen/pclose和标准文件输入/输出流中的fopen()/fclose()十分相似。
================================================================================库函数:pclose();
原型:int pclose(FILE *stream);
返回值:返回系统调用wait4()的状态。
如果stream无效,或者系统调用wait4()失败,则返回-1。注意此库函数等待管道进程运行结束,然后关闭文件流。库函数pclose()在使用popen()创建的进程上执行wait4()函数,它将破坏管道和文件系统、。
================================================================================流管道的例子- #include<stdio.h>
- #include<unistd.h>
- #include<stdlib.h>
- #include<fcntl.h>
- #define BUFSIZE 1024
- int main(int argc, char *argv[])
- {
- FILE *fp;
- char *cmd = "ps -ef";
- char buf[BUFSIZE];
- buf[BUFSIZE] = '\0';
- if ((fp = popen(cmd, "r")) == NULL)
- perror("popen");
- while ((fgets(buf, BUFSIZE, fp)) != NULL)
- printf("%s", buf);
- pclose(fp);
- exit(0);
- }
命名管道(FIFO)
基本概念
命名管道和一般的管道基本相同,但也有一些显著的不同:
A、命名管道是在文件系统中作为一个特殊的设备文件而存在的。
B、不同祖先的进程之间可以通过管道共享数据。
C、当共享管道的进程执行完所有的I/O操作以后,命名管道将继续保存在文件系统中以便以后使用。
管道只能由相关进程使用,它们共同的祖先进程创建了管道。但是,通过FIFO,不相关的进程也能交换数据。
命名管道创建
=============================================================================
#include
#include
int mkfifo(const char *pathname,mode_t mode);
返回:若成功则为0,若出错返回-1
一旦已经用mkfifo创建了一个FIFO,就可用open打开它。确实,一般的文件I/O函数(close,read,write,unlink等)都可用于FIFO。当打开一个FIFO时,非阻塞标(O_NONBLOCK)产生下列影响:
(1)在一般情况中(没有说明O_NONBLOCK),只读打开要阻塞到某个其他进程为写打开此FIFO。类似,为写而打开一个FIFO要阻塞到某个其他进程为读而打开它。
(2)如果指一了O_NONBLOCK,则只读打开立即返回。
但是,如果没有进程已经为读而打开一个FIFO,那么只写打开将出错返回,其errno是ENXIO。类似于管道,若写一个尚无进程为读而打开的
FIFO,则产生信号SIGPIPE。若某个FIFO的最后一个写进程关闭了该FIFO,则将为该FIFO的读进程产生一个文件结束标志。
FIFO相关出错信息:
EACCES(无存取权限)
EEXIST(指定文件不存在)
ENAMETOOLONG(路径名太长)
ENOENT(包含的目录不存在)
ENOSPC(文件系统余空间不足)
ENOTDIR(文件路径无效)
EROFS(指定的文件存在于只读文件系统中)
=============================================================================命名管道实例:fifo_write.c
阅读(3549) | 评论(0) | 转发(1) |