用管道来进行进程间通信是通过pipe函数,管道只能支持父子进程或有公共祖先的进程之间通信。
pipe函数原型:
#include <unistd.h>
int pipe (int fd[2]);
该函数被调用后,会通过fd数组传出两个文件描述符fd[0]和fd[1],其中fd[0]为读而打开,fd[1]为写而打开。从fd[0]中读的数据,就是往fd[1]中写的数据。
当父进程调用fork后,子进程继承了父进程的文件描述符fd[0]和fd[1]。这样就建立了父子进程之间的IPC通道。父进程往fd[1]中写数据时,子进程就可以通过fd[0]读到。
下面代码描述的是上图的流程
父进程
1:fork出自进程
2:从标准输入读入数据
3:将数据通过fd[1]写入管道
子进程
1:通过fd[0]从管道读入数据
2:将数据写到标准输出
#include <stdio.h>
#include <unistd.h>
int main () {
int buflen;
char* buffer[1024];
pid_t pid;
int fd[2];
if (pipe(fd) < 0) {
printf ("pipe error\n");
return 1;
}
if ((pid = fork()) < 0) {
printf ("pipe error\n");
return 1;
}
if (pid > 0) { //father
close (fd[0]);
while ((buflen = read (STDIN_FILENO, buffer, 1024)) > 0) {
write (fd[1], buffer, buflen);
}
return 0;
}
else {
close (fd[1]);
while ((buflen = read (fd[0], buffer, 1024)) > 0) {
write (STDOUT_FILENO, buffer, buflen);
}
return 0;
}
}
图中1 2 3 4 5 6分别为:
1是父进程标准输入(STDIN_FILENO)
2是父进程的fd1[1]
3是子进程的fd1[0],同时也是子进程的标准输入
4是子进程的fd2[1],同时也是子进程的标准输出
5是父进程的fd2[0]
6是父进程的标准输出(STDOUT_FILENO)
父进程流程:
1:fork创建子进程
2:主循环中不断从标准输入中读取数据
3:通过fd1[1]将读入的数据写入管道
4:通过fd2[0]从管道中读入数据
5:将数据写到标准输出
子进程流程:
1:调用dup2函数复制文件描述符fd1[0]为标准输入
2:复制文件描述符fd2[1]为标准输出
3:调用execl函数执行新的程序coproces,进入coproces主循环,该程序由coproces.c编译而成,功能是英文字符大小写转换。
4:在coproces主循环中不断从标准输入读取数据
5:将数据中英文字符大小写转换后写入标准输出。
// coproces.c
#include <stdio.h>
#include <unistd.h>
int main () {
char buffer[1024];
int buflen;
while ((buflen = read (STDIN_FILENO, buffer, 1024)) > 0) {
int i = 0;
for (i = 0; i < buflen; ++i) {
if (isupper (buffer[i])) {
buffer[i] = tolower (buffer[i]);
}
else if (islower (buffer[i])) {
buffer[i] = toupper (buffer[i]);
}
}
write (STDOUT_FILENO, buffer, buflen);
}
}
// main.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main () {
pid_t pid;
int fd1[2], fd2[2];
int buflen;
char buffer[1024];
if (pipe (fd1) < 0 || pipe (fd2) < 0) {
printf ("pipe error!\n");
exit (1);
}
if ((pid = fork()) < 0) {
printf ("fork error !\n");
exit (1);
}
if (!pid) { // child process
close (fd1[1]); // read only
close (fd2[0]); // write only
if (STDIN_FILENO != fd1[0]) {
if(STDIN_FILENO !=dup2 (fd1[0], STDIN_FILENO)) {
printf ("error!\n");
exit (1);
}
close (fd1[0]);
}
if (STDOUT_FILENO != fd2[1]) {
if(STDOUT_FILENO != dup2 (fd2[1], STDOUT_FILENO)) {
printf ("error!\n");
exit (1);
}
close (fd2[1]);
}
if (execl ("./coproces", "coproces",(char*)0) < 0) {
printf ("execl error\n");
exit (1);
}
}
// parent process
close (fd1[0]); //write only
close (fd2[1]); //read only
while ((buflen = read (STDIN_FILENO, buffer, 1024)) > 0) {
if (buflen != write (fd1[1], buffer, buflen)) {
printf ("write to fd1 error!\n");
exit (1);
}
buflen = read (fd2[0], buffer, 1024);
write (STDOUT_FILENO, buffer, buflen);
}
exit (0);
}