Как заранее прочитать буфер stdin перед EOF в python3? - PullRequest
0 голосов
/ 01 ноября 2018

В своем коде на Python я написал следующую функцию для получения самоопределенного двоичного пакета из stdin.

def recvPkg():
     ## The first 4 bytes stands for the remaining package length
    Len = int.from_bytes(sys.stdin.buffer.read(4), byteorder='big', signed=True)
     ## Then read the remaining package
    data = json.loads(str(sys.stdin.buffer.read(Len), 'utf-8'))
     ## do something...

while True:
    recvPkg()

Затем в другой программе Node.js я порождаю эту программу на Python как дочерний процесс и отправляю ей байты.

childProcess = require('child_process').spawn('./python_code.py');
childProcess.stdin.write(someBinaryPackage)

Я ожидаю, что дочерний процесс прочитает из буфера stdin после получения пакета и выдаст вывод. Но это не работает, и я думаю, что причина в том, что дочерний процесс не начнет читать, пока его буфер stdin не получит сигнал, как EOF. В качестве доказательства, если я закрою stdin childProcess после stdin.write, код python будет работать и получать все буферизованные пакеты одновременно. Это не так, как я хочу, потому что мне нужно, чтобы стандартный дочерний процесс был открыт Так есть ли другой способ для node.js отправить сигнал childProcess для информирования о чтении из буфера stdin?

(извините за плохой английский.

1 Ответ

0 голосов
/ 02 ноября 2018

Из Википедии ( выделенная мина ):

Ввод с терминала никогда не «заканчивается» (если устройство не отключено) , но полезно ввести более одного «файла» в терминал, поэтому последовательность клавиш зарезервировано для указания конца ввода. В UNIX перевод нажатия клавиши в EOF выполняется драйвером терминала , поэтому программе не нужно отличать терминалы от других входных файлов.

Нет способа отправить символ EOF, как вы ожидаете. EOF на самом деле не персонаж, который существует. Когда вы находитесь в терминале, вы можете нажать последовательность клавиш ctrl z в Windows и ctrl d в UNIX-подобной окружающие среды. Они генерируют управляющие символы для терминала (код 26 в Windows, код 04 в UNIX) и считываются терминалом. После этого терминал (после чтения этого кода) по существу прекратит запись в программы stdin и закроет it.

В Python файловый объект будет .read() навсегда. Условие EOF состоит в том, что .read() возвращает ''. В некоторых других языках это может быть -1 или другое условие.

Рассмотрим:

>>> my_file = open("file.txt", "r")
>>> my_file.read()
'This is a test file'
>>> my_file.read()
''

Последний символ здесь не EOF, там просто ничего нет. Python имеет .read() до конца файла и не может .read() больше.

Потому что stdin в специальном типе «file» не имеет конца. Вы должны определить этот конец. Терминал определил этот конец как управляющие символы, но здесь вы не передаете данные в stdin через терминал, вам придется управлять им самостоятельно.

Просто закрыв файл

Вход [...] никогда не «заканчивается» (если устройство не отключено)

Закрытие stdin, пожалуй, самое простое решение здесь. stdin - это бесконечный файл, поэтому, как только вы закончите запись в него, просто закройте его.

Ожидайте свой собственный управляющий персонаж

Другой вариант - определить свой собственный управляющий персонаж. Вы можете использовать все, что вы хотите здесь. В приведенном ниже примере используется байт NULL.

питон
class FileWithEOF:
    def __init__(self, file_obj):
        self.file = file_obj
        self.value = bytes()
    def __enter__(self):
        return self
    def __exit__(self, *args, **kwargs):
        pass
    def read(self):
        while True:
            val = self.file.buffer.read(1)
            if val == b"\x00":
                break
            self.value += val
        return self.value

data = FileWithEOF(sys.stdin).read()
Узел
childProcess = require('child_process').spawn('./python_code.py');
childProcess.stdin.write("Some text I want to send.");
childProcess.stdin.write(Buffer.from([00]));

Возможно, вы читаете неправильную длину

Я думаю, что значение, которое вы захватываете в Len, меньше длины вашего файла.

питон
import sys

while True:
    length = int(sys.stdin.read(2))
    with open("test.txt", "a") as f:
        f.write(sys.stdin.read(length))
Узел
childProcess = require('child_process').spawn('./test.py');

// Python reads the first 2 characters (`.read(2)`)
childProcess.stdin.write("10"); 

// Python reads 9 characters, but does nothing because it's
// expecting 10. `stdin` is still capable of producing bytes from
// Pythons point of view.
childProcess.stdin.write("123456789");

// Writing the final byte hits 10 characters, and the contents
// are written to `test.txt`.
childProcess.stdin.write("A");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...