Как писать в stdin другого процесса на C/C++ в Linux?

Вопрос или проблема

У меня есть одна команда (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().

Шаги для решения

  1. Создание канала (pipe): Для передачи данных между процессами, создадим анонимный канал, который будет включать в себя два дескриптора — один для записи (write), а другой для чтения (read).

  2. Создание дочернего процесса: Используя fork(), создадим дочерний процесс, который будет выполнять команду cmd_c.

  3. Перенаправление стандартного ввода: В дочернем процессе нам нужно перенаправить стандартный ввод (STDIN) на конец канала (write end), чтобы команда cmd_c могла считывать данные из него.

  4. Отправка данных из родительского процесса: В родительском процессе мы можем использовать дескриптор записи, чтобы отправлять данные в канал.

Пример кода

#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;
}

Объяснение кода

  1. pipe(): Создает канал и возвращает два дескриптора в массиве pipefd. pipefd[0] используется для чтения, а pipefd[1] — для записи.

  2. fork(): Создает новый процесс. Если это дочерний процесс, мы закрываем дескриптор записи и перенаправляем стандартный ввод на читательную часть канала с помощью dup2().

  3. execv(): Этот вызов замещает дочерний процесс новым, исполняя программу cmd_c.

  4. write() и close(): В родительском процессе мы пишем в канал и закрываем дескриптор записи, когда данные отправлены.

Вывод

Используя описанный подход, процесс A успешно передает данные через стандартный ввод в cmd_c, обеспечивая корректное взаимодействие между процессами. Это решение демонстрирует эффективный метод межпроцессного взаимодействия в среде Linux, являясь важным инструментом в разработке системного программного обеспечения.

Оцените материал
Добавить комментарий

Капча загружается...