Search code examples
pythonjsonnamed-pipesmkfifo

Python read JSON from named pipe/FIFO


I'm trying to read JSON data from a FIFO as in the code below:

import os
import errno
import json

FIFO = '/tmp/vision'

try:
    os.mkfifo(FIFO)
except OSError as oe: 
    if oe.errno != errno.EEXIST:
        raise

print("Opening FIFO...")
while True:
    with open(FIFO) as fifo:
        for line in fifo:
            #line = '{"humans": []}' # WORKS FINE
            print(line)
            perception_output = json.loads(line)
            print(perception_output)
            print(type(perception_output))

I'm constantly pushing on the other side (C++ code) of the FIFO one-line JSONs. The delimiter is "\n". The strange thing is that I can successfully load the first line and print it as Python dictionary as in the log below, but on the second line I observe the following error:

me@pc:~/vision$ python3 brain.py 
Opening FIFO...
{ "humans": [ ] }

{'humans': []}
<class 'dict'>
{ "humans": [ ] }

Traceback (most recent call last):
  File "brain1.py", line 19, in <module>
    perception_output = json.loads(line)
  File "/usr/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

If I hardcode the "line" variable as commented I have no issues. What could be the problem?

Edit: Adding the C++ code of the FIFO Writer:

#include <fcntl.h>
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    int fd;
    const char * myfifo = "/tmp/vision";
    fd = open(myfifo, O_WRONLY);

    if (fd <= 0) {
        throw std::logic_error("Cannot open FIFO fd");
    }

    while (true) {
        std::string json_out = "{ \"humans\": [ ] }\n";
        std::cout << json_out << std::endl;

        if (write(fd, json_out.c_str(), strlen(json_out.c_str()) + 1) < 0) 
        {
            throw std::logic_error("Cannot write to FIFO fd");
        }
    }
}

Solution

  • strlen(json_out.c_str()) + 1) is your culprit. You should do strlen(json_out.c_str()) or even better json_out.length(). The last element of every c string is the invisible \0 char which you then send to the server's side. And that \0 char then becomes the first element of new line which json decoder doesn't understand.