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

У меня есть две программы на 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, чтобы поместить его в переменную. Если бы я мог, я мог бы проанализировать переменную и продолжить свой путь.

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

Благодарю вас!


person data-dancer    schedule 15.04.2018    source источник


Ответы (1)


Вы можете запустить socat без блокировки, используя низкоуровневый класс Popen в python. Вам нужно перенаправить 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()
person tdelaney    schedule 16.04.2018
comment
Ты жжешь! Потрясающе и как раз то, что мне было нужно. Я проголосовал за, но у меня мало баллов SO, поэтому на общедоступной странице не отображается повышение. - person data-dancer; 16.04.2018
comment
Я заметил, что ваше редактирование изменилось на for line in iter(socat_proc.stderr.readline,''):. Мое решение не сработало? Я знаю, что некоторые люди используют эту форму для труб, но я в целом не видел необходимости. - person tdelaney; 28.04.2018