Почему, когда я использую dup2 () перед fork (), это не работает?

#c #shell #fork #dup2

#c #оболочка #fork #dup2

Вопрос:

Я хочу создать оболочку и хочу обрабатывать несколько каналов. Я пытался понять, как работают dup2 () и fork. Обычно fork() создает новый дочерний процесс, который точно такой же, как и отец. Но когда я использую dup2 перед fork, кажется, что это работает не так, как я думаю, что это должно делать. Но когда я использую dup2() в дочернем процессе, это работает… Я не понимаю, потому что обычно fork создает копию вызывающего процесса…

Кто-нибудь может объяснить почему?

Это не работает:

 int fd = open("toto.txt", O_RDONLY);
char str[10] = {0};
int test[2] = {0, 0};
char *av[] = {"/bin/ls", NULL};

pipe(test);
dup2(test[1], 1);
if (fork() == 0) {
    execve(av[0], av, env);
}
else {
    wait(NULL);
    read(test[0], str, 10);
    write(1, str, 10);
}
  

но это работает :

 int fd = open("toto.txt", O_RDONLY);
char str[10] = {0};
int test[2] = {0, 0};
char *av[] = {"/bin/ls", NULL};

pipe(test);
if (fork() == 0) {
    dup2(test[1], 1);
    execve(av[0], av, env);
}
else {
    wait(NULL);
    read(test[0], str, 10);
    write(1, str, 10);
}
  

Комментарии:

1. Что должен делать тот, который не работает?

2. Первый должен работать, но я не понимаю, почему он не работает

3. Определите работу . Что он должен делать, чего не делает? Что он делает вместо этого?

4. Предполагалось, что на терминале будет отображаться 10 первых символов моей команды ls, но это ничего не делает. Это потому, что я использую dup2 () перед fork, но я не понимаю, почему это не работает в этом случае

5. Почему вы ожидаете, что ваш первый будет отображать что-либо на терминале? Вы меняете, к какому стандартному выводу (FD 1) относится.

Ответ №1:

Оригинал работает некорректно, потому что:

 dup2(test[1], 1);
if (fork() == 0) {
    execve(av[0], av, env);
}
else {
    wait(NULL);
    read(test[0], str, 10);
    write(1, str, 10);
}
  

После dup2 стандартного вывода перенаправляется в канал. Это перенаправление применяется как к родительскому, так и к дочернему. Из-за этого строка:

     write(1, str, 10);
  

записывает свои данные обратно в канал, а не исходный стандартный вывод (который теряется).

Перемещая dup2 в после fork() , и только в дочерний процесс, исходный стандартный вывод родительского процесса остается в покое. В этом случае перенаправляется только стандартный вывод дочернего элемента.

Примечание: вызов wait перед чтением канала будет работать для небольшого трафика канала, как в примере, но не будет работать для большого трафика. Проблема в том, что канал имеет ограниченный буфер. Как только буфер заполнен, канал начинает блокировать записи. wait Будет ждать завершения дочернего элемента, но дочерний элемент будет ждать в канале, чтобы быть прочитанным родителем. Это может привести к тупиковой ситуации, когда трафик достаточно велик.

Комментарии:

1. Спасибо за ваш ответ! Что мне нужно сделать, чтобы обрабатывать большой трафик?

2. @Progear да, чтобы обрабатывать большой трафик, вы должны прочитать канал, прежде чем ждать завершения дочернего процесса. В вашем случае замените read и wait