Как определить, какая пара псевдотерминалов подключена друг к другу?

У меня есть две программы на Python, которые должны общаться друг с другом через последовательное соединение. Чтобы смоделировать соединение, я создаю двунаправленный поток байтов, используя socat, как здесь:

socat -d -d pty,raw,echo=0 pty,raw,echo=0

Консоль возвращает следующее, указывая два pty-порта, которые теперь соединены вместе:

2018/04/15 22:33:03 socat[18197] N PTY is /dev/pts/2
2018/04/15 22:33:03 socat[18197] N PTY is /dev/pts/3
2018/04/15 22:33:03 socat[18197] N starting data transfer loop with FDs [5,5] and [7,7]

Затем мне нужно вручную изменить каждую из двух программ, чтобы указать последовательное соединение для каждой, например:

В программе A.py:

import serial
...
ser = serial.Serial('/dev/pts/2')

В программе B.py:

import serial
...
ser = serial.Serial('/dev/pts/3')

Мне нужен скрипт, который установит соединение socat, затем выполнит A.py с одним номером порта, переданным ему в качестве аргумента, и выполнит B.py с другим номером порта, переданным ему в качестве аргумента.

Я пробовал скрипт bash, но socat блоки команд, и я не могу перехватить его вывод stderr, чтобы поместить его в переменную. Если бы я мог, я мог бы тогда разобрать переменную и быть на моем веселом пути.

Есть идеи? Или, может быть, лучший способ сделать это?

Спасибо!

1 ответ

Решение

Вы можете запустить socat без блокировки используя низкий уровень Popen класс в питоне. Вам нужно перенаправить stderr так что вы можете отсканировать это имя pty, но затем вы можете передать его фоновому потоку после того, как получите нужную информацию.

import sys
import subprocess as subp
import threading
import shutil
import re

socat_proc = subp.Popen(['socat', '-d', '-d', 'pty,raw,echo=0', 'pty,raw,echo=0'],
    stderr=subp.PIPE)

try:
    # scan output for 2 ptys
    ptylist = []
    for line in socat_proc.stderr:
        line = line.decode().strip()
        print(line)
        pty = re.search(r"N PTY is (.+)", line)
        if pty:
            ptylist.append(pty.group(1))
            if len(ptylist) == 2:
                break

    if socat_proc.poll() is not None:
        print("badness. socat dead.")
        exit(2)

    # background thread consumes proc pipe and sends to stdout
    socat_thread = threading.Thread(target=shutil.copyfileobj, 
        args=(socat_proc.stdout, sys.stdout))
    socat_thread.daemon = True
    socat_thread.start()

    print("pty", ptylist)

    # now you can start your programs...

finally:
    socat_proc.terminate()
Другие вопросы по тегам