Вопрос или проблема
У меня есть одна команда (cmd_c
), которая может получать ввод из STDIN и обрабатывать входные данные.
Я хочу вызвать эту команду в process A
, и process A
предоставит данные для cmd_c
.
process A
вызывает fork()
+ execv()
, чтобы запустить дочерний процесс для выполнения команды cmd_c
, но я не нашел правильного способа отправить данные из process A
в cmd_c
?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main()
{
int pid;
/* продолжение */
if ((pid = fork()) > 0) {
/// делает что-то еще
/// Как отправить данные в STDIN дочернего процесса???
wait(NULL);
} else {
char *arg_list[] = {"./cmd_c", NULL};
int rc = execv("./cmd_c", arg_list);
printf("Дочерний execv = %d\n", rc);
}
return 0;
}
Команда cmd_c.c
выглядит следующим образом,
#include <stdio.h>
int main()
{
char buf[256];
while (fgets(buf, sizeof(buf) - 1, stdin)) {
printf("XXXXXXXXX %s\n", buf);
}
return 0;
}
Спасибо.
Ответ или решение
Для решения задачи передачи данных от одного процесса (Процесса A) к другому (cmd_c) в Linux на языке C/C++, необходимо использовать механизм создания каналов (pipe). Этот подход позволяет создать специальный файл, который будет служить промежуточным буфером, в который один процесс может записывать данные, а другой процесс может читать их.
Ниже приводится подробное решение этой задачи с корректной реализацией использования pipe()
, fork()
, и execv()
.
Шаги для решения
-
Создание канала (pipe): Для передачи данных между процессами, создадим анонимный канал, который будет включать в себя два дескриптора — один для записи (write), а другой для чтения (read).
-
Создание дочернего процесса: Используя
fork()
, создадим дочерний процесс, который будет выполнять командуcmd_c
. -
Перенаправление стандартного ввода: В дочернем процессе нам нужно перенаправить стандартный ввод (STDIN) на конец канала (write end), чтобы команда
cmd_c
могла считывать данные из него. -
Отправка данных из родительского процесса: В родительском процессе мы можем использовать дескриптор записи, чтобы отправлять данные в канал.
Пример кода
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main() {
int pipefd[2]; // Массив для хранения дескрипторов канала
pid_t pid;
// Создаем анонимный канал
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork(); // Создаем дочерний процесс
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) { // Дочерний процесс
// Закрываем дескриптор записи
close(pipefd[1]);
// Перенаправляем STDIN на конец канала
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
// Исполняем команду cmd_c
char *arg_list[] = {"./cmd_c", NULL};
execv("./cmd_c", arg_list);
perror("execv"); // В случае ошибки
exit(EXIT_FAILURE);
} else { // Родительский процесс
// Закрываем дескриптор чтения
close(pipefd[0]);
// Записываем данные в канал
const char *data = "Hello, cmd_c\n";
write(pipefd[1], data, strlen(data));
// Закрываем дескриптор записи
close(pipefd[1]);
// Ждем завершения дочернего процесса
wait(NULL);
}
return 0;
}
Объяснение кода
-
pipe(): Создает канал и возвращает два дескриптора в массиве
pipefd
.pipefd[0]
используется для чтения, аpipefd[1]
— для записи. -
fork(): Создает новый процесс. Если это дочерний процесс, мы закрываем дескриптор записи и перенаправляем стандартный ввод на читательную часть канала с помощью
dup2()
. -
execv(): Этот вызов замещает дочерний процесс новым, исполняя программу
cmd_c
. -
write() и close(): В родительском процессе мы пишем в канал и закрываем дескриптор записи, когда данные отправлены.
Вывод
Используя описанный подход, процесс A успешно передает данные через стандартный ввод в cmd_c, обеспечивая корректное взаимодействие между процессами. Это решение демонстрирует эффективный метод межпроцессного взаимодействия в среде Linux, являясь важным инструментом в разработке системного программного обеспечения.