0

我是unix新手。在下面的代码中,我从命令行“~$ foo last sort more”传递了三个参数,以复制“~$ last | sort | more”。我正在尝试创建一个需要三个参数的程序(现在至少 3 个)。父进程将分叉三个进程。第一个进程将写入管道。第二个进程将从管道读取和写入,第三个进程将从管道读取并写入标准输出(终端)。第一个进程将执行“last”,第二个进程将执行“sort”,第三个进程将执行“more”,进程将休眠 1,2 和 3 秒以进行同步。我很确定我在创建管道和重定向输入和输出时遇到了麻烦。我不 没有任何输出到终端,但我可以看到进程已经创建。我会很感激一些帮助。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>

#define FOUND       1
#define NOT_FOUND   0
#define FIRST_CHILD 1
#define LAST_CHILD  numargc
#define PATH_1 "/usr/bin/"
#define PATH_2 "/bin/"

#define DUP_READ()                             \
if (dup2(fdes[READ], fileno(stdin)) == -1)     \
            {                              \
                perror("dup error");       \
                exit(4);                   \
            }                              

#define DUP_WRITE()                            \
if (dup2(fdes[WRITE], fileno(stdout)) == -1)   \
                {                              \
                    perror("dup error");       \
                    exit(4);                   \
                }                              

#define CLOSE_FDES_READ()   \
close(fdes[READ]);

#define CLOSE_FDES_WRITE()   \
close(fdes[WRITE]);

#define EXEC(x, y)                                          \
if (execl(arraycmds[x], argv[y], (char*)NULL) == -1)        \
                {                                           \
                    perror("EXEC ERROR");                   \
                    exit(5);                                \
                }
#define PRINT                         \
printf("FD IN:%d\n", fileno(stdin));    \
printf("FD OUT:%d\n", fileno(stdout));

enum 
{
    READ, /* 0 */
    WRITE,
    MAX
};

int cmdfinder( char* cmd, char* path); /* 1 -> found, 0 -> not found */
int main (int argc, char* argv[])
{

    int numargc=argc-1;
    char arraycmds[numargc][150];
    int i=1, m=0, sleeptimes=5, numfork;
    int rc=NOT_FOUND;
    pid_t pid;
    int fdes[2];

    if(pipe(fdes) == -1)
    {
        perror("PIPE ERROR");
        exit(4);
    }

    while(i <= numargc)
    {
        memset(arraycmds[m], 0, 150);
        rc=cmdfinder(argv[i], arraycmds[m]);
        if (rc)
        {
            printf("Command found:%s\n", arraycmds[m]);
        } 
        i++;
        m++;
    }

    i=0; //array index
    numfork=1; //fork number

    while(numfork <= numargc)
    {
        if ((pid=fork()) == -1)
        {
            perror("FORK ERROR");
            exit(3);
        }
        else if (pid == 0)
        {
            /* Child */

            sleep(sleeptimes);

            if (numfork == FIRST_CHILD)
            {
                DUP_WRITE();
                EXEC(i, numfork);
            }
            else if (numfork == LAST_CHILD)
            {

                DUP_READ();
                CLOSE_FDES_WRITE();
                EXEC(i, numfork);
            }
            else 
            {

                DUP_READ();
                DUP_WRITE();
                CLOSE_FDES_READ();
                CLOSE_FDES_WRITE();

                EXEC(i, numfork);
            }
        }
        else 
        {
            /* Parent */
            printf("pid:%d\n", pid);    
            i++;
            numfork++;
            sleeptimes++;
        }
    }

    PRINT;
    printf("i:%d\n", i);
    printf("numfork:%d\n", numfork);
    printf("DONE\n");       
    return 0;
}


int cmdfinder(char* cmd, char* path)
{
    DIR* dir;
    struct dirent *direntry; 
    char *pathdir;
    int searchtimes=2; 

    while (searchtimes)
    {
        pathdir = (char*)malloc(250);
        memset(pathdir, 0, 250);

        if (searchtimes==2)
        {
            pathdir=PATH_1;
        }
        else
        {
            pathdir=PATH_2;
        }

        if ((dir  = opendir(pathdir)) == NULL)
        {
            perror("Directory not found");
            exit (1);
        }
        else
        {
            while (direntry = readdir(dir))
            {
                if (strncmp( direntry->d_name, cmd, strlen(cmd)) == 0)
                {
                    strcat(path, pathdir);
                    strcat(path, cmd);
                    //searchtimes--;
                    return FOUND;
                }
            }
        }
        closedir(dir);
        searchtimes--;
    }
    printf("%s: Not Found\n", cmd);
    return NOT_FOUND;
}
4

1 回答 1

0

你所有的宏都比你直接写的更难阅读。特别是当它们引用局部变量时。要了解EXEC我的眼睛发生了什么,必须从它习惯的地方跳到它定义的地方,找出它使用的本地数组,然后再跳回去看看该访问如何适应main. 这是一个宏的迷宫。

哇,cmdfinder?您自己的$PATH查找,只是它是硬编码的/usr/bin:/bin?双哇,readdir只是为了找出是否存在名称已经确定的文件?就stat这样吧!或者不做任何事情,只需执行它并ENOENT通过尝试下一个来处理它。或者使用execlp这就是它的用途!

说到重点......你没有足够的管道,而且你没有关闭所有未使用的描述符。

last | sort | more是由 2 个管道连接的 3 个命令的管道。你不能用一根管子做到这一点。第一个命令应该写入第一个管道,中间命令应该读取第一个管道并写入第二个管道,最后一个命令应该读取第二个管道。

您可以先创建两个管道,然后执行所有分叉,这使得事情变得简单,但在每个子进程中都需要很多closes,因为它们都会继承所有管道 fd。或者您可以使用更复杂的循环,在派生将使用它的第一个进程之前创建每个管道,并在创建相关子进程后立即关闭父进程中的每个描述符。我不想看到您为此使用了多少宏。

每个成功的 dup 之后都应该关闭所复制的描述符。dup是“复制”的缩写,而不是“移动”。完成后,您还剩下一个额外的描述符,所以不要只是dup2(fdes[1], fileno(stdout)- 也是close(fdes[1])在之后。(为了完全健壮,您应该检查是否fdes[1]==fileno(stdout)已经,在这种情况下跳过dup2and close。)

后续问题

您不能将一个管道用于 3 个进程,因为无法区分哪些数据应该发送到哪个目的地。当第一个进程写入管道时,而其他两个进程都试图从中读取数据,其中一个进程将获取数据,但您将无法预测哪个进程。您需要中间进程读取第一个进程写入的内容,最后一个进程读取中间进程写入的内容。

关于在分叉后共享文件描述符,您说对了一半。实际的管道对象是共享的。这就是使整个系统工作的原因。但是文件描述符 - 由小整数指定的端点,如标准输出的 1,标准输入的 0,等等 - 并没有按照您建议的方式耦合。同一个管道对象可能在两个进程中关联同一个文件描述符号,关联是独立的。在一个进程中关闭 fd 1 不会导致 fd 1 在任何其他进程中关闭,即使它们是相关的。

共享 fd 表,以便一个任务中的关闭对另一个任务产生影响,是“pthread”功能集的一部分,而不是“fork”功能集的一部分。

于 2013-07-30T23:44:30.430 回答