Alesfatalis Alesfatalis - 19 days ago 11
C Question

Send data from C Parent to Python Child and back using a Pipe

So I am trying to send a string from my C parent process to my python child process over a Pipe created by the parent. After that, I want to send back a string from my python child back to the parent and print it there.

This is my C-Code:


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

int main(int argc, char **argv, char **envp) {
pid_t childpid;
int status;
int test;
char *argument;
int fd[2];
char *numbers = "3,5,7\n";

argument = "./fork.py";
char *python[] = {argument, NULL};

test = 0;

pipe(fd); //Create pipe

childpid = fork();

if (childpid==(-1) ) {
perror( "fork" );
return -1;
} else if (childpid==0) {
//in child
execvp(argument, python);
}

//in parent
write(fd[1], numbers, sizeof(numbers));
close(fd[1]);

waitpid(-1, &status, 0); //Wait for childprocess to finish
char buffer[1024];

while (read(fd[0], buffer, sizeof(buffer)) != 0) {} //Read pipe to buffer

if (test < 0) { //If failed print error message or success message
printf("Error: %s\n", buffer);
} else {
printf("%s\n", buffer);
}

return 0;
}


This is my Python Code(fork.py):


#!/usr/bin/env python3
import os
import sys

def main():
r, w = os.pipe()
os.read(r, 12)
os.close(r)
os.write(w, "This is a test")
os.close(w)
sys.exit(0)


if __name__ == '__main__':
main()


What am I doing wrong since the pipe should be forked and therefore accessible by the child? It seems like there is no data passed to the pipe or the python process can't access the pipe somehow to retrieve the data. And yes it has to be a pipe.

Answer

You are generating a new pair of pipe-handles in python. You have to use the same handles you created in C.

Create one pair for communicating from C to python, and another for the communication from Python to C:

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

int main(int argc, char **argv, char **envp) {
    pid_t childpid;
    int status;
    int test;
    int fd_a[2], fd_b[2];
    char *numbers = "3,5,7\n";

    test = 0;

    pipe(fd_a); //Create pipe
    pipe(fd_b);
    childpid = fork();

    if (childpid==(-1) ) {
        perror( "fork" );
        return -1;
    } else if (childpid==0) {
        //in child
        char *argument = "./fork.py";
        char fd0[20], fd1[20];
        snprintf(fd0, 20, "%d", fd_a[0]);
        snprintf(fd1, 20, "%d", fd_b[1]);
        close(fd_a[1]);
        close(fd_b[0]);
        char *python[] = {argument, fd0, fd1, NULL};
        execvp(argument, python);
    }
    close(fd_a[0]);
    close(fd_b[1]);

    //in parent
    write(fd_a[1], numbers, sizeof(numbers));
    close(fd_a[1]);

    waitpid(-1, &status, 0); //Wait for childprocess to finish
    char buffer[1024];

    while (read(fd_b[0], buffer, sizeof(buffer)) != 0) {} //Read pipe to buffer

    if (test < 0) { //If failed print error message or success message
        printf("Error: %s\n", buffer);
    } else {
        printf("%s\n", buffer);
    }

    return 0;
}

Taking the arguments in python and use these as handles:

#!/usr/bin/env python3
import os
import sys

def main():
    r, w = map(int, sys.argv[1:])
    os.read(r, 12)
    os.close(r)
    os.write(w, b"This is a test")
    os.close(w)
    sys.exit(0)


if __name__ == '__main__':
    main()
Comments