Python процесс ввода / вывода с использованием каналов - PullRequest
0 голосов
/ 10 сентября 2018

Я пишу программу на C ++, которая будет запускать интерпретатор Python 3 как дочерний процесс, затем подключать два анонимных канала Linux - один к его stdout и stderr, а второй к stdin интерпретатора; далее общайтесь с ним по этим каналам.

Мне нужно запустить Python в интерактивном режиме, то есть передать ему одну команду с помощью входного канала и дождаться ответа на выходном канале. Все бы хорошо, но кажется, что Python может работать в интерактивном режиме, только если он stdout и stdin подключен к tty.

Цитата документов Python:

Интерпретатор работает подобно оболочке Unix: при вызове со стандартным вводом, подключенным к tty-устройству, он читает и выполняет команды в интерактивном режиме; при вызове с аргументом имени файла или с файлом в качестве стандартного ввода он читает и выполняет сценарий из этого файла.

Действительно, когда я запускаю интерпретатор с каналами вместо tty, я не вижу ничего в ответном канале после отправки команды.

Итак, могу ли я каким-то образом обойти такое поведение и заставить интерпретатор python3 работать точно так, как он был запущен с терминала пользователем?

Опять проблема в двух словах:

Мне нужно интегрировать Python в мое приложение на сервере C ++, чтобы клиенты могли выполнять команды python. Встраивание интерпретатора в сервер выглядит плохой идеей, в основном по соображениям безопасности (пользователи могут повредить сервер или его данные, кроме того, сервер работает с некоторыми привилегиями, которые я не хочу предоставлять пользователям).

Другое возможное решение - использовать интерпретатор в режиме CLI (командный режим). Основная проблема заключается в том, что мне нужно импортировать некоторые модули и предварительно выполнить некоторый код, чтобы предоставить свою серверную среду и немного API для пользователей. Это будет слишком тяжело сделать перед вызовом интерпретатора с каждой командой (эти действия довольно сложные, включая установление сетевого соединения)

Таким образом, запуск интерпретатора в отдельном процессе и взаимодействие сервера с ним с использованием механизмов IPC выглядит неплохой идеей.

В любом случае, я буду рад взглянуть на ваши предложения, если они у вас есть.

Ответы [ 3 ]

0 голосов
/ 10 сентября 2018

Если вам действительно нужен дочерний процесс, чтобы думать, что он разговаривает с терминалом, вы можете сделать это с помощью псевдотерминала или pty.Существует два разных API, один из BSD Unix и один из System V, и Linux поддерживает оба.См. Что означают pty и tty? или посмотрите справочные страницы для forkpty или posix_openpt.

Однако в этом случае я предполагаю, что интерпретатор python выполняет блочную буферизациюего вывод.Вы можете проверить это, вызвав его с помощью -u, чтобы отключить буферизацию в stdin / stdout.

0 голосов
/ 13 сентября 2018

Вы делаете что-то действительно странное и необычное. Интерактивная оболочка предназначена для интерактивного использования, с набором команд человеком. Он не предназначен для интерактивных сценариев, когда входные данные поступают из другой программы.

С учетом сказанного, да, вы можете сделать это, хотя я действительно не рекомендовал бы это. Вам нужно запустить скрипт, который читает stdin для команд, а затем вызвать метод exec ().

Простая версия может выглядеть так:

while True:
    lines = []
    while True:
        line = input()
        if line == "":
            exec("\n".join(lines))
            break
        else:
            lines.append(line)

Приведенная выше программа ведет себя аналогично оболочке python при получении многострочного ввода, в этом интерактивные команды буферизуются и не выполняются до тех пор, пока не появятся последовательные пустые символы новой строки.

Для использования в сценариях / в программах вам, вероятно, нужен маркер блока, который немного более надежен, чем двойные переводы строки. Например, вы можете вместо этого разбивать блоки команд пустым символом, чтобы можно было безопасно выполнять сценарии, содержащие пустые строки.

FWIW, я согласен с Джоном Кугельманом , что в любом случае это похоже на неправильный вопрос. Вероятно, есть лучший и более простой способ решить вашу настоящую проблему, чем делать что-то подобное. Что вы действительно пытаетесь сделать?

0 голосов
/ 10 сентября 2018

Вы можете использовать python в любом случае, каждый раз, когда запускается команда, введенная пользователем, или архивировать их в файл и запускать для каждой введенной строки. Таким образом, вы можете использовать его вывод более просто. Надеюсь быть полезным.

...