jeanluca has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I need to setup a communication link between a C program and a perl program. This C program executes the perl script and reads the output from the perl script. This perl script writes its output to a file-descriptor
#! /usr/bin/perl open OUT ,">&63" ; print OUT "this is a message\n" ; close OUT ;
At the end of this post I've attached the C program.
Anyway, this doesn't work at all. However, when I use 0 instead of 63, everything works fine!!

Any suggestions what I'm doing wrong here with the file-descriptor 63 ?

Thnx a lot
LuCa

C program:
#include <unistd.h> #include <stdio.h> #include <fcntl.h> main() { const int RESPONSE_FD = 63; int pfd[2], status, size; char buffer[100]; status = pipe(pfd); if(status == -1) { printf("Could not open pipe\n"); exit(1); } else { printf("The filedescriptors are: %d %d\n", pfd[0], pfd[1]); } status = fork(); if(status == 0) { printf("This is the child\n"); status = dup2(pfd[0], RESPONSE_FD); if(status == -1) { printf("dup2 failed\n"); exit(1); } close(pfd[1]); close(pfd[0]); while(read(STDIN_FILENO, buffer, sizeof(buffer))>0) { printf("%s", buffer); } } else { printf("This is the parent\n"); system("my_prog.pl"); } }

Replies are listed 'Best First'.
Re: communication between C and perl
by almut (Canon) on Feb 09, 2007 at 14:06 UTC

    Hi jeanluca, I think you just got it the wrong way round :)   You have to dup the output side of the pipe to file descriptor 63 (my_prog.pl needs to write to the output side...), and then simply read from the input side within your C program. Also, it's more common to swap the roles of parent and child, i.e. run the command in the child (via one of the exec functions), and read its output in the parent process. Here's a modified version of your program that should work (with my_prog.pl as you had it):

    #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/wait.h> int main() { const char *cmd = "./my_prog.pl"; const int RESPONSE_FD = 63; int pfd[2], status; char buffer[100]; int rv; status = pipe(pfd); if(status == -1) { printf("Could not open pipe\n"); exit(1); } else { printf("The filedescriptors are: %d %d\n", pfd[0], pfd[1]); } status = fork(); if(status == 0) { printf("This is the child\n"); /* dup output/writing side of pipe */ status = dup2(pfd[1], RESPONSE_FD); /* close unused input side */ close(pfd[0]); if(status == -1) { printf("dup2 failed\n"); exit(1); } execl(cmd, cmd, (char *)0); } else { printf("This is the parent\n"); /* close unused output side of pipe */ close(pfd[1]); /* read from input side */ while(read(pfd[0], buffer, sizeof(buffer))>0) { printf("%s", buffer); } wait(&rv); fprintf(stderr,"%s exited with value %d\n", cmd, rv); } return 0; }

    Output:

    The filedescriptors are: 4 6 This is the child This is the parent this is a message ./my_prog.pl exited with value 0

    Update: minor fixes, so that it also does compile with -Wall :)

      Yes!!!
      Thanks a lot, I really really appreciate it!!
      And it wasn't even a perl problem!!

      LuCa
Re: communication between C and perl
by Joost (Canon) on Feb 09, 2007 at 09:47 UTC
    I'm not sure what that program is supposed to do, but I think you're getting bitten by this (from my system() manpage):
    The context in which the utility is ultimately executed may differ from that in which system() was called. For example, file descriptors that have the FD_CLOEXEC flag set are closed, and the process ID and parent process ID are different. Also, if the executed utility changes its environment variables or its current working directory, that change is not reflected in the caller’s context.

Re: communication between C and perl
by jesuashok (Curate) on Feb 09, 2007 at 10:35 UTC
    generally, I create a named pipe file and make those two programs contact with each other by using the pipe file name.
Re: communication between C and perl
by jeanluca (Deacon) on Feb 09, 2007 at 12:06 UTC
    I'm not so good with C, but I'm really interested how that works with the named pipes.
    If a small example is too much to ask, may be a link ?

    Thnx LuCa
      Try these. They are super simple and don't take errors and broken-pipe conditions into account. Start the c program, then start the perl program. The perl program could be launched from c if you wanted.
      #include <stdio.h> int main(void) { FILE *fp; /* char *line; updated correction */ char line[256]; if (mkfifo ("age-pipe", 0755) != 0) {printf ("Could not make this fifo\n");} else {printf ("FIFO was successfully made!\n");} fp = fopen ("age-pipe", "r"); for(;;){ fgets (line,256, fp); printf ("message: %s\n", line); } close (fp); }
      #!/usr/bin/perl use strict; use warnings; open(FIFO, "> age-pipe") or die $!; select FIFO; $|=1; select STDOUT;$|=1; my $input = 'a'; while(1){ print "Enter your age:\n"; #my $input = <STDIN>; print FIFO "$input\n"; sleep(1); $input++ } close(FIFO);

      I'm not really a human, but I play one on earth. Cogito ergo sum a bum
        When I run your example I get
        ~/tmp/cperl> ./a.out FIFO was successfully made! Segmentation fault
        I get the segmentation fault (from the c program) when I start the perl script :(

        Anyway, what is so different about this approach and simply using the number 63 ?

        LuCa