|
Home > Archive > Unix Programming > August 2005 > problem passing messages between processes
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
problem passing messages between processes
|
|
| djbitchpimp@snowboard.com 2005-08-18, 5:54 pm |
| I am trying to write a program that forks a child process, exec's a new
process in the child, and then passes messages back and forth between
the parent and child. The process that is exec'd takes messages on
stdin and sends them out on stdout.
If I remove the exec, I can pass messages back and forth between
processes using pipes. But as soon as I run the exec, I cannot retrieve
any messages coming back from the child.
This is what the code looks like:
nt main (void) {
// declare pipes
int pipe1 [2], pipe2 [2] ;
pid_t childPID ;
char msgBuf [50] ;
int bytes_written ;
pipe (pipe1) ;
pipe (pipe2) ;
// fork a new process
if ((childPID = fork ()) == 0) {
/* this is the child process */
// close appropriate ends of pipe in child process
close (pipe1 [1]) ; // pipe1 [0] for reading from parent
close (pipe2 [0]) ; // pipe2 [1] for writing to parent
// exec here
read (pipe1 [0], msgBuf, sizeof (msgBuf)) ;
printf ("Child received message: %s\n", msgBuf) ;
char *ack = "Acknowledgment" ;
bytes_written = write (pipe2 [1], ack, strlen (ack)) ;
if (bytes_written < 0) {
printf ("WRITE FAILED\n") ;
}
else {
printf ("%d bytes written to parent process\n", bytes_written) ;
}
}
else {
/* this is the parent process */
// close appropriate ends of pipe in parent process
close (pipe1 [0]) ; // pipe1 [1] for output to child (writing)
close (pipe2 [1]) ; // pipe2 [0] for input from child (reading)
// send a request
char *request = "http://www.playboy.com 10.0.0.1/- - GET" ;
printf ("Sending the following string to squidGuard process:\n") ;
printf ("%s\n", request) ;
bytes_written = write (pipe1 [1], request, strlen (request) + 1) ;
if (bytes_written < 0) {
printf ("WRITE FAILED\n") ;
}
else {
printf ("%d bytes written to child process\n", bytes_written) ;
}
// get response
read (pipe2 [0], msgBuf, sizeof (msgBuf)) ;
printf ("Parent received message: %s\n", msgBuf) ;
// wait for child process to exit
wait () ;
}
}
My question is: Is read the correct way to retrieve messages from a
child on stdin? Also, the child program is written to just send the
output to stdout, there is nothing in the code to send it to another
process. Is it possible to make this work?
| |
| Pascal Bourguignon 2005-08-18, 5:54 pm |
| djbitchpimp@snowboard.com writes:
> I am trying to write a program that forks a child process, exec's a new
> process in the child, and then passes messages back and forth between
> the parent and child. The process that is exec'd takes messages on
> stdin and sends them out on stdout.
>
> If I remove the exec, I can pass messages back and forth between
> processes using pipes. But as soon as I run the exec, I cannot retrieve
> any messages coming back from the child.
>
> This is what the code looks like:
> [... code with absolutely no reference to stdin ...]
> My question is: Is read the correct way to retrieve messages from a
> child on stdin?
No. The correct way to read something from stdin is to use one of the
stdio input functions that use stdin by default, or to explicitely
pass stdin to one of the stdio input functions that take a stream.
> Also, the child program is written to just send the
> output to stdout, there is nothing in the code to send it to another
> process. Is it possible to make this work?
Of course. Stop sending random messages to the stdout, with statements like:
printf ("Child received message: %s\n", msgBuf) ;
and do send the data to the stdout stream instead of the pipe.
bytes_written = write (1, ack, strlen (ack)) ;
Now since you want to use stdin and stdout in the child to communicate
with the parent, you'd better use dup2(2) to map the pipes to the file
descriptors 0 and 1 under stdin and stdout (option 0).
Then use stderr for your debugging messages.
When you exec, the variables pipe1 and pipe2 disappear. But not the
file descriptors they refer to, since these file descriptors live in
the kernel memory that is kept by exec. So you could either
"hardcode" the file descriptor, using dup2(2), or pass them in the
argv:
/* option 1 */
dup2(pipe1[0],10); /* input */
dup2(pipe2[1],11); /* output */
execl("/some/path/pgm","pgm",0);
/* and in pgm.c: */
const int input_fd=10;
const int output_fd=11;
read(input_fd,...);
write(output_fd,...);
/* option 2 */
char instr[64],outstr[64];
sprintf(instr,"%d",pipe1[0]);
sprintf(outstr,"%d",pipe2[1]);
execl("/some/path/pgm","pgm","--input-fd",instr,"--output-fd",outstr,0);
/* and in pgm.c: */
int input_fd=parse_arguments(argv,"--input-fd","%d");
int output_fd=parse_arguments(argv,"--output-fd","%d");
read(input_fd,...);
write(output_fd,...);
Of course, if "pgm" is designed only to work as a subprogram of your
program, it would be simplier to just use stdin and stdout.
/* option 0 */
dup2(pipe1[0],0); /* stdin */
dup2(pipe2[1],1); /* stdout */
execl("/some/path/pgm","pgm",0);
/* and in pgm.c: */
read(0,...)
write(1,...)
or:
fread(stdin,...); /* or */ fscanf(stdin,...); /* or */ gets(...);
fwrite(stdout,...); /* or */ fprintf(stdout,...); /* or */ print(...);
--
__Pascal Bourguignon__ http://www.informatimago.com/
Grace personified,
I leap into the window.
I meant to do that.
| |
| djbitchpimp@snowboard.com 2005-08-18, 5:54 pm |
| Pascal Bourguignon wrote:
....
> /* option 0 */
> dup2(pipe1[0],0); /* stdin */
> dup2(pipe2[1],1); /* stdout */
> execl("/some/path/pgm","pgm",0);
>
> /* and in pgm.c: */
> read(0,...)
> write(1,...)
> or:
> fread(stdin,...); /* or */ fscanf(stdin,...); /* or */ gets(...);
> fwrite(stdout,...); /* or */ fprintf(stdout,...); /* or */ print(...);
>
>
>
> --
> __Pascal Bourguignon__ http://www.informatimago.com/
> Grace personified,
> I leap into the window.
> I meant to do that.
The problem is that I am not writing the code for the process I am
exec'ing - it is already written and I cannot change any of the code.
It reads from stdin and writes to stdout. Is option 0 the only option
and will it still work in this case?
| |
| Gordon Burditt 2005-08-18, 5:54 pm |
| >I am trying to write a program that forks a child process, exec's a new
>process in the child, and then passes messages back and forth between
>the parent and child. The process that is exec'd takes messages on
>stdin and sends them out on stdout.
Beware of buffering issues and protocol deadlock.
>If I remove the exec, I can pass messages back and forth between
>processes using pipes. But as soon as I run the exec, I cannot retrieve
>any messages coming back from the child.
>
>This is what the code looks like:
>
>nt main (void) {
>
> // declare pipes
> int pipe1 [2], pipe2 [2] ;
> pid_t childPID ;
> char msgBuf [50] ;
> int bytes_written ;
>
> pipe (pipe1) ;
> pipe (pipe2) ;
> // fork a new process
> if ((childPID = fork ()) == 0) {
> /* this is the child process */
>
> // close appropriate ends of pipe in child process
> close (pipe1 [1]) ; // pipe1 [0] for reading from parent
> close (pipe2 [0]) ; // pipe2 [1] for writing to parent
>
A child inherits stdin, stdout, and stderr from file descriptors
0, 1, and 2, respectively. It's traditional here to do
a little dance with closing descriptors 0, 1, and 2, and
using dup() to make descriptors 0, 1, and 2 the ones you want.
Then close pipe1[0] and pipe2[1] as you've now got copies
in 0 and 1.
You *CAN* pass pipe1[0] and pipe2[1] to the exec'd program
via command line options, but it's clumsy.
> // exec here
>
> read (pipe1 [0], msgBuf, sizeof (msgBuf)) ;
> printf ("Child received message: %s\n", msgBuf) ;
>
> char *ack = "Acknowledgment" ;
> bytes_written = write (pipe2 [1], ack, strlen (ack)) ;
>
> if (bytes_written < 0) {
> printf ("WRITE FAILED\n") ;
> }
> else {
> printf ("%d bytes written to parent process\n", bytes_written) ;
> }
> }
> else {
> /* this is the parent process */
>
> // close appropriate ends of pipe in parent process
> close (pipe1 [0]) ; // pipe1 [1] for output to child (writing)
> close (pipe2 [1]) ; // pipe2 [0] for input from child (reading)
>
> // send a request
> char *request = "http://www.playboy.com 10.0.0.1/- - GET" ;
>
> printf ("Sending the following string to squidGuard process:\n") ;
> printf ("%s\n", request) ;
>
> bytes_written = write (pipe1 [1], request, strlen (request) + 1) ;
>
> if (bytes_written < 0) {
> printf ("WRITE FAILED\n") ;
> }
> else {
> printf ("%d bytes written to child process\n", bytes_written) ;
> }
>
> // get response
> read (pipe2 [0], msgBuf, sizeof (msgBuf)) ;
> printf ("Parent received message: %s\n", msgBuf) ;
>
> // wait for child process to exit
> wait () ;
> }
>}
>
>My question is: Is read the correct way to retrieve messages from a
>child on stdin? Also, the child program is written to just send the
>output to stdout, there is nothing in the code to send it to another
>process. Is it possible to make this work?
If stdout is connected to a pipe, this will just work. But you have
to set up file descriptor 1 to be the pipe you want.
Gordon L. Burditt
| |
| Pascal Bourguignon 2005-08-18, 8:50 pm |
| djbitchpimp@snowboard.com writes:
> Pascal Bourguignon wrote:
> ...
>
> The problem is that I am not writing the code for the process I am
> exec'ing - it is already written and I cannot change any of the code.
> It reads from stdin and writes to stdout. Is option 0 the only option
> and will it still work in this case?
Yes.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
|
|
|
|
|