Каков наилучший способ создать канал RW с C ++? - PullRequest
3 голосов
/ 12 августа 2010

У меня есть программа A, которая должна отправлять команды на стандартный ввод программы B и считывать выходные данные этой программы B. (Программирование на C ++, не только для Linux)

ProgramA -> отправить письмоA -> ProgramB ProgramA <- вывод B <- ProgramB </p>

У меня фактически есть первая часть, отправка команд B, работа с popen ().Я знаю, что popen - это только один способ.

Итак, как лучше всего использовать два способа, используя c ++?

Ответы [ 3 ]

4 голосов
/ 12 августа 2010

Используя функциональность posix (то есть будет работать на linux и любой системе, которая соответствует стандарту posix), вы можете использовать комбинацию pipe / execl / dup. Короче, что происходит, это:

  • создать 2 канала (один для чтения и один для записи ребенку)
  • форк текущего процесса. Это сохраняет открытым тот же FD
  • закрыть текущий стандарт / стандартный вывод. Затем используйте dup (который использует самый низкий доступный дескриптор для дублирования того, что вы ему даете)
  • execl дочерний процесс

Обратите внимание, что необходимы некоторые сбросы. Код родителя:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main ()
{
    pid_t pid;
    int pipe_in[2];   /* This is the pipe with wich we write to the child process. */
    int pipe_out[2];  /* This is the pipe with wich we read from the child process. */

    if (pipe (pipe_in) || pipe (pipe_out)) {
        fprintf (stderr, "Error in creating pipes!\n");
        exit (1);
    }

    /* Attempt to fork and check for errors */
    if ((pid = fork ()) == -1) {
        fprintf (stderr, "Error in fork!\n");
        exit (1);
    }

    if (pid) {
        /* The parent has the non-zero PID. */
        char temp[100];
        int result;
        FILE* child_in;
        FILE* child_out;

        child_in = fdopen(pipe_out[0],"r");
        child_out = fdopen(pipe_in[1],"w");
        close(pipe_out[1]);
        close(pipe_in[0]);

        fprintf(child_out, "something\n"); 

        fgets(temp,100,child_in);
        printf(" Read from child %s \n", temp); 

        /* Send a command to the child. */
        fprintf(child_out, "quit\n"); 
        fflush(child_out);

        fgets(temp,100,child_in);
        printf(" Read from child %s \n", temp);

        wait (&result);             /* Wait for child to finish */
    }
    else {
        /* The child has the zero pid returned by fork*/
        close (1);
        dup (pipe_out[1]);  /* dup uses the lowest numbered unused file descriptor as new descriptor. In our case this now is 1. */

        close (0);          /* dup uses the lowest numbered unused file descriptor as new descriptor. In our case this now is 0. */
        dup (pipe_in[0]);  

        close (pipe_out[0]);
        close (pipe_out[1]);
        close (pipe_in[0]);
        close (pipe_in[1]);
        execl ("child", "child", NULL);
        exit(1); /* Only reached if execl() failed */
    }
    return 0;
}

Простой ребенок это:

#include <stdio.h>
#include <string.h>

int main ()
{
    char temp[100];

    do {
        printf ("In child: \n");
        fflush (stdout);
        fgets (temp, 100, stdin);
        printf ("Child read %s\n", temp);
        fflush (stdout);
    } while (!strstr (temp, "quit"));

    return 0;
}

Вы можете скомпилировать их с помощью:

gcc -o parent parent.c
gcc -o child child.c
./parent

и вы увидите

Чтение от ребенка У ребенка: Читать от ребенка Ребенок читать бросить

1 голос
/ 12 августа 2010

Вы можете попробовать g_spawn_async_with_pipes из Glib.

Эта функция запускает процесс и возвращает его дескрипторы файлов ввода / вывода.

Я использую его в своей программе на C ++:

gchar** cmd_argv;
g_shell_parse_argv("your command", &cmd_argc, &cmd_argv, NULL);
g_spawn_async_with_pipes
 (NULL, //Working directory, Inherited from parent (our program)
  cmd_argv,
  NULL, //Null to inherit environment variables from parent
  G_SPAWN_SEARCH_PATH, //Flags
  NULL,
  NULL,
  NULL, //Returns the process ID of child (which runs from our program)
  &stdin_fd, //Standard input (file descriptor)
  &stdout_fd, //Standard output (file descriptor)
  &stderr_fd, //Standard error (file descriptor)
  NULL); //GError*

...

//we have to free cmd_argv
for (int i = 0; i < cmd_argc; ++i) g_free (cmd_argv [i]);

stdin_fd, stdout_fd и stderr_fd являются целыми числами (как дескрипторы файлов):

gchar* out;
GIOChannel* io = g_io_channel_unix_new(stdout_fd); //g_io_channel_win32_new_fd
while(g_io_channel_read_line(io, &out, NULL, NULL, NULL) == G_IO_STATUS_NORMAL)
{
    //...
    g_free(out);
}

Однако это не библиотека C ++, но может быть полезной (когда вы хотите написатьПриложение GTK в C ++).

0 голосов
/ 12 августа 2010

См. здесь для очень тесно связанного вопроса от Джереми Сика (который работает над многими библиотеками boost).Тогда (в 2002 году), кажется, единственный ответ, который был достаточно близок к ответу на ваш вопрос, можно найти в библиотеках ACE.См. здесь для получения дополнительной информации.

Не уверен, что это правильный ответ на ваш вопрос, но это может помочь.

...