31

如何在 Python 中创建临时 FIFO(命名管道)?这应该有效:

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/NamedTemporaryFile 创建的文件上运行它时。

4

6 回答 6

29

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(如果他们有适当的权限)之前创建,如果错误/异常没有得到正确处理,这可能会导致您的程序崩溃。

于 2009-09-16T02:09:15.307 回答
6

您可能会发现使用以下上下文管理器很方便,它会为您创建和删除临时文件:

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
    try:
        yield filename
    finally:
        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")
于 2019-02-26T22:13:14.580 回答
4

怎么用

d = mkdtemp()
t = os.path.join(d, 'fifo')
于 2009-09-16T01:36:12.090 回答
3

如果它用于您的程序中,而不是用于任何外部,请查看Queue 模块。作为一个额外的好处,python 队列是线程安全的。

于 2009-09-16T01:42:29.407 回答
1

实际上,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")
于 2015-09-16T00:34:37.503 回答
-1

为什么不直接使用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)
于 2009-09-16T01:37:37.860 回答