#include <unistd.h> int pipe (int fd121) ; //Returns: 0 if OK, -1 on error I
fd[0] reading, fd[1] writing
管道的典型用途
为两个不同进程(父子)提供进程间通信手段。一个进程创建一个管道,调用fork。如下图所示
Next, the parent process closes the read end of one pipe, and the child process closes the write end of that same pipe. This provides a one-way flow of data between the two processes 父进程关闭读管道,子进程关闭写管道,提供单向数据流
管道命令,在不同的进程之间传递数据流
When we enter a command such as
who | sort |lp
to a Unix shell, the shell performs the steps described previously to create three processes with two pipes between them
系统创建三个命令和两条管道
创建双向数据流的步骤
1. create pipe 1 (fd1[0] and fd1[1]), create pipe 2 (fd2[0] and fd2[1]),
2. fork,
3. parent closes read end of pipe 1 (fd1[0]),
4. parent closes write end of pipe 2 (fd2[1]),
5. child closes write end of pipe 1 (fd1[1]), and
6. child closes read end of pipe 2 (fd2[0]).
示例:
将文件名传递给server,server解析文件内容,传回给client
mainpipe.c
#include "unpipc.h" void client(int, int), server(int, int); int main(int argc, char **argv) { int pipe1[2], pipe2[2]; pid_t childpid; Pipe(pipe1); /* create two pipes */ Pipe(pipe2); if ( (childpid = Fork()) == 0) { /* child */ Close(pipe1[1]); Close(pipe2[0]); server(pipe1[0], pipe2[1]); exit(0); } /* 4parent */ Close(pipe1[0]); Close(pipe2[1]); client(pipe2[0], pipe1[1]); Waitpid(childpid, NULL, 0); /* wait for child to terminate */ exit(0); } void client(int readfd, int writefd) { size_t len; ssize_t n; char buff[MAXLINE]; /* 4read pathname */ Fgets(buff, MAXLINE, stdin); len = strlen(buff); /* fgets() guarantees null byte at end */ if (buff[len-1] == '\n') len--; /* delete newline from fgets() */ /* 4write pathname to IPC channel */ Write(writefd, buff, len); /* 4read from IPC, write to standard output */ while ( (n = Read(readfd, buff, MAXLINE)) > 0) Write(STDOUT_FILENO, buff, n); } void server(int readfd, int writefd) { int fd; ssize_t n; char buff[MAXLINE+1]; /* 4read pathname from IPC channel */ if ( (n = Read(readfd, buff, MAXLINE)) == 0) err_quit("end-of-file while reading pathname"); buff[n] = '\0'; /* null terminate pathname */ if ( (fd = open(buff, O_RDONLY)) < 0) { /* 4error: must tell client */ snprintf(buff + n, sizeof(buff) - n, ": can't open, %s\n", strerror(errno)); n = strlen(buff); Write(writefd, buff, n); } else { /* 4open succeeded: copy file to IPC channel */ while ( (n = Read(fd, buff, MAXLINE)) > 0) Write(writefd, buff, n); Close(fd); } }
以上介绍的是半全工管道。下面介绍全双工管道
半全工
双全工(solaris)
例子:
#include "unpipc.h" int main(int argc, char **argv) { int fd[2], n; char c; pid_t childpid; Pipe(fd); /* assumes a full-duplex pipe (e.g., SVR4) */ if ( (childpid = Fork()) == 0) { /* child */ sleep(3); if ( (n = Read(fd[0], &c, 1)) != 1) err_quit("child: read returned %d", n); printf("child read %c\n", c); Write(fd[0], "c", 1); exit(0); } /* 4parent */ Write(fd[1], "p", 1); if ( (n = Read(fd[1], &c, 1)) != 1) err_quit("parent: read returned %d", n); printf("parent read %c\n", c); exit(0); }
创建一个管道同时启动另外一个进程,该进程从管道读出标准输入,或向改管道写入标准输出
#include <stdio.h> FILE *popen (const char *command, const char *type) ; //Returns: file pointer if OK, on error int pclose (FILE *stream) ; //Returns: termination status of shell or -1 on error
command是一个shell命令行,由shall程序处理,path环境变量可以定位command。popen在调用进程和做指定的命令之间创建一个管道。
type:r,调用进程读command的标准输出
type:w,调用进程写command的标准输入
#include "unpipc.h" int main(int argc, char **argv) { size_t n; char buff[MAXLINE], command[MAXLINE]; FILE *fp; /* 4read pathname */ Fgets(buff, MAXLINE, stdin); n = strlen(buff); /* fgets() guarantees null byte at end */ if (buff[n-1] == '\n') n--; /* delete newline from fgets() */ snprintf(command, sizeof(command), "cat %s", buff); fp = Popen(command, "r"); /* 4copy from pipe to standard output */ while (Fgets(buff, MAXLINE, fp) != NULL) Fputs(buff, stdout); Pclose(fp); exit(0); }