Подтвердить что ты не робот

Создайте временный FIFO (named pipe) в Python?

Как создать временный FIFO (named pipe) в Python? Это должно работать:

import tempfile

temp_file_name = mktemp()
os.mkfifo(temp_file_name)
open(temp_file_name, os.O_WRONLY)
# ... some process, somewhere, will read it ...

Однако я не решаюсь из-за большого предупреждения в Python Docs 11.6 и возможного удаления, поскольку он устарел.

EDIT. Примечательно, что я пробовал tempfile.NamedTemporaryFile (и по расширению tempfile.mkstemp), но os.mkfifo throws:

OSError -17: Файл уже существует

когда вы запустите его в файлах, созданных mkstemp/NamedTemporaryFile.

4b9b3361

Ответ 1

os.mkfifo() завершится с ошибкой OSError: [Errno 17] File exists, если файл уже существует, поэтому здесь нет проблемы с безопасностью. Проблема с безопасностью с использованием tempfile.mktemp() - это условие гонки, когда злоумышленник может создать файл с тем же именем, прежде чем открывать его самостоятельно, но поскольку os.mkfifo() завершается с ошибкой, если файл уже существует, это не проблема.

Однако, поскольку mktemp() устарел, вы не должны его использовать. Вместо этого вы можете использовать tempfile.mkdtemp():

import os, tempfile

tmpdir = tempfile.mkdtemp()
filename = os.path.join(tmpdir, 'myfifo')
print filename
try:
    os.mkfifo(filename)
except OSError, e:
    print "Failed to create FIFO: %s" % e
else:
    fifo = open(filename, 'w')
    # write stuff to fifo
    print >> fifo, "hello"
    fifo.close()
    os.remove(filename)
    os.rmdir(tmpdir)

EDIT: я должен четко указать, что, поскольку уязвимость mktemp() предотвращается этим, все еще существуют другие обычные проблемы безопасности, которые необходимо учитывать; например злоумышленник мог бы создать fifo (если бы у них были подходящие разрешения) до того, как ваша программа заработала, что может привести к сбою вашей программы, если ошибки/исключения неправильно обрабатываются.

Ответ 2

Как насчет использования

d = mkdtemp()
t = os.path.join(d, 'fifo')

Ответ 3

Если он используется в вашей программе, а не с любыми внешними, посмотрите на Queue module. В качестве дополнительного преимущества очереди python являются потокобезопасными.

Ответ 4

Возможно, вам будет удобно использовать следующий менеджер контекста, который создает и удаляет временный файл для вас:

import os
import tempfile
from contextlib import contextmanager


@contextmanager
def temp_fifo():
    """Context Manager for creating named pipes with temporary names."""
    tmpdir = tempfile.mkdtemp()
    filename = os.path.join(tmpdir, 'fifo')  # Temporary filename
    os.mkfifo(filename)  # Create FIFO
    yield filename
    os.unlink(filename)  # Remove file
    os.rmdir(tmpdir)  # Remove directory

Вы можете использовать это, например, так:

with temp_fifo() as fifo_file:
    # Pass the fifo_file filename e.g. to some other process to read from.
    # Write something to the pipe 
    with open(fifo_file, 'w') as f:
        f.write("Hello\n")

Ответ 5

Фактически, все, что mkstemp делает, запускается mktemp в цикле и продолжает пытаться создавать исключительно до тех пор, пока это не удастся (см. исходный код stdlib здесь). Вы можете сделать то же самое с os.mkfifo:

import os, errno, tempfile

def mkftemp(*args, **kwargs):
    for attempt in xrange(1024):
        tpath = tempfile.mktemp(*args, **kwargs)

        try:
            os.mkfifo(tpath, 0600)
        except OSError as e:
            if e.errno == errno.EEXIST:
                # lets try again
                continue
            else:
                raise
        else:
           # NOTE: we only return the path because opening with
           # os.open here would block indefinitely since there 
           # isn't anyone on the other end of the fifo.
           return tpath
    else:
        raise IOError(errno.EEXIST, "No usable temporary file name found")

Ответ 6

Почему бы просто не использовать mkstemp()?

Например:

import tempfile
import os

handle, filename = tempfile.mkstemp()
os.mkfifo(filename)
writer = open(filename, os.O_WRONLY)
reader = open(filename, os.O_RDONLY)
os.close(handle)