管道 pipes
#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);
}
popen函数
创建一个管道同时启动另外一个进程,该进程从管道读出标准输入,或向改管道写入标准输出
#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);
}