Передача канала в качестве параметра в exec - PullRequest
0 голосов
/ 04 марта 2011

Я пытаюсь передать канал другому процессу, который я создаю с помощью execv.Это мой код, но он не работает.Я искал повсюду информацию, но я не могу найти что-то конкретное о прохождении трубы через exec.Любая помощь приветствуется.Спасибо

int fd[2];
pipe(fd);

char passwrite[1];
sprintf(passwrite, "%d", fd[0]);

char arg[1];
arg[1]=passwrite;

int x;
x=fork();
if (x==0) {
execv("NewProg",arg);
}

Ответы [ 4 ]

6 голосов
/ 04 марта 2011

Канал - это однонаправленное соединение, которое обычно оказывается между двумя процессами, связанными общим предком, обычно первым из двух создаваемых процессов, если только это не оболочка, в этом случае оболочка создает канал и имеет двадети, которые используют трубу.Канал имеет конец записи, который используется одним процессом;у него есть конец чтения, используемый другим.Часто проще всего организовать подключение стандартного выхода одного процесса к стандартному входу другого.Также проще всего использовать файловые дескрипторы, а не стандартные файловые потоки ввода / вывода.

Последовательность операций:

  1. Вызов pipe() для создания канала.
  2. Вызовите fork() для создания дочернего элемента.
  3. Дочерний процесс (возвращаемое значение 0 из fork()) выполняет:
    • close() конец записи канала
    • dup2() конец чтения канала для стандартного ввода
    • close() конец чтения канала
    • execve() дочерний процесс, который будет читать из канала (егостандартный ввод)
  4. Родительский процесс (возвращаемое значение> 0 из fork()) выполняет:
    • close() конец чтения канала
    • dup2() конец записи канала в стандартный вывод.
    • close() конец записи канала
    • execve() процесс, который будет записывать в канал (его стандартный вывод)

Обратите внимание, что в этом случае вы закрываете оба файловых дескриптора, возвращенных вызовом pipe(), и закрываете их дважды(один раз в родительском, один раз в дочернем).

Если родительский процесс должен писать дочернему элементу через файловый поток, используйте вызов fdopen() в дескрипторе файла записи (и не используйте dup2() на нем или close() на нем - вы закрываете его с fclose() в потоке файлов, возвращаемом fdopen(), или выходом).

Если вы хотите сообщить дочернему процессу, какой файлномер дескриптора, с которого он может прочитать входные данные из канала, тогда вам не нужно делать dup2() в дочернем элементе;вы можете просто отформатировать строку в массиве символов (во множественном числе - вам нужно как минимум символы и должно быть около дюжины или около того, поскольку это очень дешево), и вы можете затем организовать передачу аргументов в execve()функция.Помните, что ребенку нужно как минимум три указателя: один для argv [0], название программы;один для номера дескриптора файла;и один для завершающего нулевого указателя.Вот как execve() знает, когда он достиг конца списка аргументов.Если вы используете execv(), применяются те же комментарии;вы просто не можете определить среду ребенка (например, список переменных среды, которые он получает);он просто получит ту же среду, которая была у родительского процесса во время fork().

Первый шаг в каждом из ¶3 и ¶4 является решающим.Если вы их опустите, труба не будет работать должным образом.

1 голос
/ 04 марта 2011

человек труба

Здесь вы можете найти пример использования трубы

1 голос
/ 04 марта 2011

Есть пара потенциальных проблем с вашим кодом, даже до того, как вы перейдете к обработке каналов (см. ответ Джонатана Леффлера ).Во-первых, вам нужен больший буфер, так как одного символа недостаточно для хранения целого числа и завершающего NUL:

char passwrite[10];

Тогда arg должен быть массивомуказателей, а не массив символов, и он также должен быть больше:

char *arg[3];

Вам нужно поместить в аргументы конкретные вещи:

arg[0] = "NewProg"; // name of program
arg[1] = passwrite;
arg[2] = NULL;

Страница руководства для execv в моей системе объясняет это более подробно:

const char * arg и последующие эллипсы в функциях execl (), execlp () и execle () можно рассматривать как arg0,arg1, ..., argn.Вместе они описывают список из одного или нескольких указателей на строки с нулевым символом в конце, которые представляют список аргументов, доступных для исполняемой программы.Первый аргумент, по соглашению, должен указывать на имя файла, связанное с исполняемым файлом.Список аргументов должен заканчиваться указателем NULL, и, поскольку это функции с переменным числом, этот указатель должен быть приведен (char *) NULL.

0 голосов
/ 04 марта 2011

Для этого вам потребуется использовать системный вызов dup (). Также вам потребуется изменить STDIN, STDOUT OF parent и child согласно требованию. Это отрывок из оболочки Unix, которую я создал .

void pipe() {int z;
int w=fork();

 if(w==0)
 {    
     int pfd[2];
     pipe(pfd[2]);
     z=fork();
     if(z==0)
     {
         close(pfd[0]);
         close(1);
         dup(pfd[1]);
         close(pfd[1]);
         execlp(token[0],token[0],NULL);
     }
     else
         {
               close(pfd[1]);
               close(0);
               dup(pfd[0]);
               close(pfd[0]);
               execlp(token[2],token[2],NULL);
         }     
  }
  else
       wait();

}

В приведенном выше коде вам нужно заменить токен [0], токен [2] и токен [1], которые являются элементами указателей на строки (в моей оболочке), командой, которую вы хотите запустить. Как я уже делал парсинг поэтому в командной строке моей оболочки пришлось использовать токен [0/1/2] для получения различных параметров командной строки. Но вы можете заменить их, чтобы эта работа работала

...