zainosaurus
zainosaurus

Reputation: 148

Sending data from C process to Python process using pipes

I'm trying to send data from a C program to a python program (both are running simultaneously). I'm attempting to use the popen function in C. The way I understand it, whatever I write to the file descriptor in C can be read from stdin in the python program. However, the python program appears to hang at the point where it reads from stdin. Any suggestions?

Here's the C program:

test.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(void) {

    FILE * fp = popen("sudo python display.py", "w");
    if (fp == NULL) {
        printf("popen error\n");
        exit(1);
    }

    int inc = 0;
    char buf[10];

    while(1) {
        sprintf(buf, "%d", inc);
        fputs(buf, fp);
        inc++;
        sleep(1);
    }


    return (0);
}

Here is the python program, which should read the value of "inc" and output it

display.py

import sys

value = 0

while(True):
    value = sys.stdin.read()
    print value

The program seems to hang at value = sys.stdin.read(). I have tried readline() and readlines() as well with the same result.

Upvotes: 3

Views: 2026

Answers (2)

You rather should use fprintf(3) instead of mixing sprintf (which is unsafe, prefer snprintf(3)) with fputs.

You really want to output whole lines (because textual protocols are so convenient to debug). And use readline on the Python side.

At last, a FILE* obtained by popen(3) is not even guaranteed to be line-buffered (but could have a much larger buffer, perhaps 4Kbytes or more). You might set its buffer using setvbuf(3) but you really should flush explicitly the FILE* buffer with fflush(3). If you don't, the output could stay in the buffer for a long time (without any actual write(2) done by stdio functions like fprintf or fputs) so the pipe(7) stays empty.

(so you have problems even on the C side)

The program seems to hang at value = sys.stdin.read().

I guess that not a single byte was actually written by your C code (you could check by using strace(1)) because your fputs stayed in the buffer. You might need to wait a long time (perhaps 1000 seconds, to fill a buffer of a few kilobytes) to have it actually write something on the pipe, because you forgot the fflush .

A popen-ed file should absolutely be pclosed.

So you should replace your (incorrect) while loop with:

while(1) {
    fprintf(fp, "%d\n", inc);
    inc++;
    fflush(fp);
    sleep(1);
}

And your loop should be exited somehow. Perhaps you might catch some signal(7) -probably SIGTERM- (but be sure to read signal-safety(7)). Be sure to pclose (to avoid zombie processes).

(I am assuming you are on Linux or some other POSIX system)

Upvotes: 3

John La Rooy
John La Rooy

Reputation: 304127

readline() would work if you were outputting lines from your C program.

Since you never print a newline, readline will wait forever.

read() with no parameters will wait until the C program exits (or otherwise closes stdout). Again this is never going to happen with your program

Upvotes: 4

Related Questions