Открытие именованного канала в одном модуле, чтение в другом

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

Я использую операцию FIFO для отправки «сигнала» (простой T/F) от одного модуля к другому. Один модуль открывает FIFO для записи в него, а другой открывает FIFO для чтения из него. Цель здесь состоит в том, чтобы модуль чтения немедленно читал и отображал, как только модуль записи получает команду сделать это. Модуль записи открывает FIFO, но модуль чтения этого не делает.

Возможно ли то, что я пытаюсь сделать? Я пытаюсь запустить обе операции в _threads, чтобы поддерживать несколько процессов в каждом модуле. Обратите внимание, что оба модуля находятся в классах, которые я не включил для краткости (объясняя «я»).

оригинальный модуль отправки

def pipe_relay(self):
    FIFO = 'pipe_relay'
    thread_num = num

    try:
        os.mkfifo(FIFO)
    except OSError as oe:
        if oe.errno != errno.EEXIST:
            raise

    while self.relay_switch:
        print("Opening FIFO...")
        with open(FIFO) as fifo:
            print("FIFO opened")
            while self.relay_switch:
                data = fifo.write(signal)
                if len(data) == 0:
                    print("Writer is closed")
                    break
                print('Write: "{0}"'.format(data))

обновлен модуль отправки

Я понял, что не хочу постоянно записывать в FIFO данные, которые я туда забрасывал, поэтому я удалил оператор while(). Теперь кажется, что FIFO вообще не откроется...


def pipe_relay(self, num, signal):
    FIFO = 'pipe_relay'
    thread_num = num

    try:
        os.mkfifo(FIFO)
    except OSError as oe:
        if oe.errno != errno.EEXIST:
            raise

    print("Opening FIFO...")

    # does not proceed past this point

    with open(FIFO, mode = 'w') as fifo:
        print("FIFO opened")
        data = fifo.write(signal)
        if len(data) == 0:
            print("Writer is closed")
        print('Write: "{0}"'.format(data))
        fifo.close()

приемный модуль

def pipe_receive(self):
    FIFO = 'pipe_relay'

    try:
        os.mkfifo(FIFO)
    except OSError as oe:
        if oe.errno != errno.EEXIST:
            raise   

    # module proceeds to here, but no further

    with open(FIFO) as fifo:
        print("FIFO opened (receiver)")
        while True:
            data = fifo.read()
            if len(data) == 0:
                print("Writer is closed")
                break
            print('Read signal: "{0}"'.format(data))
            self.DISPLAY['text'] = data
    print("this is in 'pipe_receieve'")

РЕДАКТИРОВАТЬ

Запуск Убунту 17.04. Проект написан для интерпретатора Python 3.5.


person questionable_code    schedule 12.09.2017    source источник
comment
ОС, информация о платформе?   -  person Mad Physicist    schedule 12.09.2017
comment
я опубликую правку   -  person questionable_code    schedule 12.09.2017
comment
Когда вы запускаете модуль отправки, какие из этих операторов печати появляются? Вы уверены, что пишете в fifo?   -  person PhiloEpisteme    schedule 12.09.2017
comment
Я почти уверен, что вы должны fifo.flush() после записи. см. stackoverflow.com/questions/7048095/   -  person Rolf of Saxony    schedule 12.09.2017


Ответы (3)


Вот простые фрагменты кода отправки и получения, написанные с использованием Python 3.5.2.
Закомментируйте строку fifo.flush() и посмотрите на разницу в поведении.
С flush код получения работает в тандеме с кодом отправки.
Без него код получения код не реагирует, пока fifo не закрыт

отправить.py

import sys, os, time

path = "/tmp/my.fifo"
try:
    os.mkfifo(path)
except:
    pass
try:
    fifo = open(path, "w")
except Exception as e:
    print (e)
    sys.exit()
x = 0
while x < 5:
    fifo.write(str(x))
    fifo.flush()
    print ("Sending:", str(x))
    x+=1
    time.sleep(3)
print ("Closing")
fifo.close()
try:
    os.unlink(fifo)
except:
    pass

get.py

import os, sys

path = "/tmp/my.fifo"
try:
    fifo = open(path, "r")
except Exception as e:
    print (e)
    sys.exit()
while True:
    r = fifo.read(1)
    if len(r) != 1:
        print ("Sender Terminated")
        break
    print ("Received:", r)
fifo.close()
person Rolf of Saxony    schedule 12.09.2017

Помимо обязательной опции 'w' для отправляющего модуля, у вас также могут возникнуть проблемы с отправкой или получателем, которые не подключены. Чтобы другой процесс мог использовать fifo, и у отправителя, и у получателя должен быть открыт дескриптор fifo.

См. документацию по linux в файле fifo. Если получатель не слушает, вы получаете SIGPIPE, который обычно завершает процесс, но в случае Python он будет ждать, пока не будет подключен получатель.

Если ваш отправитель мертв, а слушатель все еще активен, он получил EOF и перестает читать.

person PhiloEpisteme    schedule 12.09.2017
comment
Интересный. Я попробую это в следующий раз - спасибо, что продолжаете помогать. Вы, ребята, помогаете мне многому научиться - person questionable_code; 12.09.2017

Я немного удивлен, что код не вызывает исключения. В вашем писателе вы делаете обычный open(FILO), не указывая параметр mode. Согласно документации, mode по умолчанию имеет значение r (только для чтения). , поэтому я ожидаю, что fifo.write(signal) поднимет IOError. Где-то ловятся исключения?

В любом случае вы должны добавить mode="w" на сторону записи, чтобы открыть FIFO для записи.

person Niobos    schedule 12.09.2017
comment
Это отличный момент. Дай мне посмотреть, что из этого получится. Спасибо за понимание - person questionable_code; 12.09.2017
comment
Подразумевается, что это выполняется в отдельном потоке, что объясняет, почему происходит сбой без возникновения видимой ошибки. - person Mad Physicist; 12.09.2017
comment
Я запустил приведенный выше код с переданными параметрами 'w' и 'r', и, похоже, он сработал. - person PhiloEpisteme; 12.09.2017
comment
@MadPhysicist запускается в отдельном потоке. У меня было очень мало опыта работы с обеими этими концепциями (IPC, потоки), но я использую модуль _thread, чтобы поддерживать работу одного процесса в каждом приложении, пока этот процесс IPC пытается выполнить свою работу. - person questionable_code; 12.09.2017