Creare un FIFO temporaneo (denominato pipe) in Python?
Domanda
Come puoi creare un FIFO temporaneo (chiamato pipe) in Python? Questo dovrebbe funzionare:
import tempfile
temp_file_name = mktemp()
os.mkfifo(temp_file_name)
open(temp_file_name, os.O_WRONLY)
# ... some process, somewhere, will read it ...
Tuttavia, sono titubante a causa del grande avvertimento in Python Docs 11.6 e potenziale rimozione perché obsoleta.
MODIFICA : è interessante notare che ho provato tempfile.NamedTemporaryFile
(e per estensione tempfile.mkstemp
), ma os .mkfifo
genera:
OSError -17: il file esiste già
quando lo esegui sui file creati da mkstemp / NamedTemporaryFile.
Soluzione
os.mkfifo ()
fallirà con l'eccezione OSError: [Errno 17] Il file esiste
se il file esiste già, quindi non c'è nessun problema di sicurezza qui. Il problema di sicurezza con l'utilizzo di tempfile.mktemp ()
è la condizione della competizione in cui è possibile per un utente malintenzionato creare un file con lo stesso nome prima di aprirlo da soli, ma poiché os.mkfifo ()
ha esito negativo se il file esiste già non è un problema.
Tuttavia, poiché mktemp ()
è deprecato, non dovresti usarlo. Puoi usare tempfile.mkdtemp ()
invece:
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: dovrei chiarire che, solo perché la vulnerabilità mktemp ()
è evitata da questo, ci sono ancora gli altri soliti problemi di sicurezza che devono essere considerati; per esempio. un utente malintenzionato potrebbe creare il quindicesimo (se avessero le autorizzazioni adeguate) prima che il programma lo facesse, il che potrebbe causare l'arresto anomalo del programma se errori / eccezioni non vengono gestiti correttamente.
Altri suggerimenti
Che ne dici di usare
d = mkdtemp()
t = os.path.join(d, 'fifo')
Se è destinato all'uso nel tuo programma e non con qualsiasi esterno, dai un'occhiata a Modulo di coda . Come ulteriore vantaggio, le code di Python sono thread-safe.
Potresti trovare utile usare il seguente gestore di contesto, che crea e rimuove il file temporaneo per te:
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
Puoi usarlo, ad esempio, in questo modo:
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")
In effetti, tutto ciò che fa mkstemp
è eseguire mktemp
in un ciclo e continua a tentare di creare esclusivamente fino a quando non riesce (vedi codice sorgente stdlib qui ). Puoi fare lo stesso con 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")
Perché non usare mkstemp () ?
Ad esempio:
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)