本篇主要介绍多管道实现,自己也写得不好,希望大家多多指点。
思路
我在这篇文章中较详细的讲解了管道的实现,但当时只涉及到一个管道,因此只需要关心对管道的read和write,并不需要关心read到什么地方去。
首先,我们在使用pipe创建管道后,需要fork一个进程,子进程用于向管道写,父进程用于向管道读(注意,顺序不能颠倒)。很有趣的一个问题是,当我们使用fork命令时,子父进程的执行顺序是不能确定的,那么是让父进程向管道读还是子进程向管道读呢?
我的理解是,由于父进程不能先于子进程结束,而如果管道中没有东西,从管道读的操作会被堵塞,可以利用这个性质让子进程先于父进程结束。具体做法就是:让父进程向管道读,子进程向管道写。由于“向管道写”操作总是先于“向管道读”操作,因此可以做到父进程结束前回收子进程的工作。
那么,我们怎么做到多管道进行操作呢?其实也不难,我们可以先把所需要的所有管道建立好,然后当子进程要进行execv操作之前,把它的输出fd指向下一个管道的输入,这样重复进行就能实现多个管道进行通讯了。
要注意的是,当进行到最后一个命令,这时候我们需要判断:若最后一个命令就是“|”,则我们需要将管道中的数据输出到屏幕即可;若最后一个命令时”>”,则需要将管道中的命令写入对应的文件中。
实现
总体来说对于管道的操作有三种情况:
1. 最开始有“<”重定向符号,接着有多个管道。
2. 一开始就是多个管道进行传输,最后输出到屏幕。
3. 通过多个管道传输后,最后重定向到指定文件。
其实这三种情况都可以写成一个函数,因为只需要对第一个命令和最后一个命令进行特殊处理即可。由于笔者很蠢,最开始没想到第一种情况,因此后面只能用修改字符串的方法曲线救国了,代码很丑,将就看吧。
pipe_command:
/*take care of pipe*/
void pipe_command() {
/*pointerindex is the index of each Command*/
int i = 1, j = 0, pointerindex[20], commandnumber = CommandInfo.index;
int pipenumber = 0, pid, pipefd[20][2];
char** P_temp;
pointerindex[0] = 0; /*the first command location*/
/*get all command's index*/
while (i <= commandnumber) {
if (CommandInfo.argv[j] == NULL) {
pointerindex[i] = j + 1;
i++;
}
j++;
}
/*if