Создать временный FIFO (именованный канал) в Python?

Как вы можете создать временный FIFO (именованный канал) в 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 и потенциального удаления, потому что оно устарело.

РЕДАКТИРОВАТЬ: Примечательно, что я пытался tempfile.NamedTemporaryFile (и, соответственно, tempfile.mkstemp), но os.mkfifo броски:

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

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

6 ответов

Решение

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)

РЕДАКТИРОВАТЬ: Я должен дать понять, что только потому, что mktemp() Это устраняет уязвимость, но есть и другие обычные проблемы безопасности, которые необходимо учитывать; например, злоумышленник может создать fifo (если у него есть подходящие разрешения) до того, как это сделала ваша программа, что может привести к ее аварийному завершению, если ошибки / исключения не обрабатываются должным образом.

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

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")

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

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

Если это для использования в вашей программе, а не с какими-либо внешними, взгляните на модуль очереди. Как дополнительное преимущество, очереди Python являются потокобезопасными.

Фактически, все это 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")

Почему бы просто не использовать 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)
Другие вопросы по тегам