What is the best way to create an rw pipe with c++?
I have a program A that needs to send commands to the stdin of a program B and reads back the output of this program B. (Programming in C++, not linux only)
ProgramA -> send letter A -> ProgramB P开发者_JAVA百科rogramA <- output of B <- ProgramB
I actually have the first part, send commands to B, working with popen(). I do know that popen is a one way only.
So, what is the best way to do the two way using c++?
Using posix functionality (so, will work on linux and any system that complies with posix standard), you can use a combination of pipe/execl/dup. In short what happens is:
- create 2 pipes (one to read and one to write to the child)
- fork the current process. This keeps open the same fd
- close the current stdin/stdout. Then use dup (which uses the lowest available descriptor to duplicate what you give to it)
- execl the child process
Pay attention some flushes are needed. The code of the parent is:
#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;
}
A simple child is:
#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;
}
You can compile them with:
gcc -o parent parent.c
gcc -o child child.c
./parent
And you will see
Read from child In child: Read from child Child read quit
You may try g_spawn_async_with_pipes
from Glib.
This function runs a process and returns its input/output file descriptors.
I use it in my C++ program:
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
and stderr_fd
are integers (as file descriptors):
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);
}
However it's not a C++ library, but may be useful (when you want to write GTK app in C++).
See here for a very closely related question from Jeremy Siek (who works on many boost libraries). Back then (in 2002), it seems the only answer that was pretty close to answering your question could be found in ACE libraries. See here for more information.
Not sure it's the right answer to your question, but it might help.
精彩评论