Сокат и богатый терминал снова

Я начинаю socat на терминале, выполнив socat - UNIX-listen:/tmp/sock

Затем я иду в другой терминал и запускаю программу (с помощью python) таким образом, что она запускается в первом терминале, вот пример:

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/sock")
proc=subprocess.Popen(['prg'], stdin=s, stdout=s, stderr=s, shell=False)
proc.wait()

Программы с простым вводом / выводом, например "cat", работают нормально, но более сложные (например, "vim" или "bash"), очевидно, не очень счастливы. Кроме того, когда я ударил Cntrl-C на первом терминале socat убит, а я бы предпочел, чтобы прерывание клавиатуры доставлялось на prg Программа (запущена в коде Python выше).

Мой вопрос: если это возможно и как это сказать socat вести себя как prg является владельцем терминала, а не socat сам.

PS. Может показаться, что этот вопрос является дубликатом этого вопроса, но это не так, потому что в этом вопросе prg вызывается напрямую socat, так что можно использовать EXEC опции.

1 ответ

Решение

Сигналы или собственность владельца не могут быть "волшебным образом" переданы через сокет.

Через AF_UNIX вы можете отправить сам дескриптор файла tty (используя sendmsg и recvmsg) и заставить принимающую сторону использовать его (а не сокет) в качестве подпроцесса ' stdout/stderr. Это не может быть сделано с простым socat, но этот метод используется внутри, например, инструментом tmux.


С простым socat самое лучшее, что вы можете сделать, это заставить его отправлять буквальный байт 0x03 (^C) при нажатии Ctrl+C (это то, что делают telnet и ssh). Вы можете проверить это, нажав Ctrl + V Ctrl+C, чтобы отправить его один раз, или запустив stty raw прежде чем соцать на ввод в "сырой режим" постоянно.

Однако этого будет недостаточно, чтобы принимающая сторона действительно поняла нажатие клавиши. Самый простой способ - проверять каждый байт вручную - отправлять SIGINT, когда он видит 0x03; в противном случае запишите это в подпроцесс 'stdin.

Однако telnetd и sshd делают добавление псевдо-tty между сокетом и подпроцессом - в Python вы можете создать его, используя os.openpty(); сторона 'slave' должна быть указана в качестве подпроцесса 'stdout / stderr, а ваш сценарий должен выполняться в цикле, копируя данные между сокетом и стороной' master '.

Этого все еще не достаточно - полнофункциональный протокол входа в систему терминала, такой как SSH или Telnet, также будет иметь сообщения для обновления измерений pty и реагирования на изменения настроек termios (например, настройка "local echo" и другие, видимые в stty).

Было бы полезно прочитать исходный код клиента telnet и сервера telnetd, например, из GNU inetutils, поскольку они делают именно это.

Другие вопросы по тегам