os.pipe()
возвращает анонимный канал или именованный канал в Windows, что очень просто и эффективно.
TCP-сокеты (как предложено user1495323 ) являются более тяжелыми: например, их можно увидеть с помощью netstat, для каждого из них требуется номер порта, а количество доступных портов ограничено 64 КБ на одноранговый узел (например, 64 КБ с локального на локальный).
С другой стороны, именованные каналы (в Windows) ограничены, потому что:
И сокеты можно обернуть в Python-совместимые файловые дескрипторы, используя makefile()
, что позволяет использовать их для перенаправления stdout или stderr . Это делает этот вариант привлекательным для некоторых случаев использования, таких как отправка stdout
из одного потока в другой.
Сокет может быть создан с автоматически назначенным номером порта, как этот (на основе превосходного Python-сокета HOWTO ):
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as input_socket:
# Avoid socket exhaustion by setting SO_REUSEADDR <https://stackoverflow.com/a/12362623/648162>:
input_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# localhost doesn't work if the definition is missing from the hosts file,
# and 127.0.0.1 only works with IPv4 loopback, but socket.gethostname()
# should always work:
input_socket.bind((socket.gethostname(), 0))
random_port_number = input_socket.getsockname()[1]
input_socket.listen(1)
# Do something with input_socket, for example pass it to another thread.
output_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# close() should not strictly be necessary here, but since connect() could fail, it avoids leaking fds
# in that case. "If a file descriptor is given, it is closed when the returned I/O object is closed".
with output_socket:
output_socket.connect((socket.gethostname(), random_port_number))
Пользователь input_socket
(например, другой поток) может затем сделать:
with input_socket:
while True:
readables, _, _ = select.select([input_socket], [], [input_socket], 1.0)
if len(readables) > 0:
input_conn, addr = self.input_socket.accept()
break
with input_conn:
while True:
readables, _, errored = select.select([input_conn], [], [input_conn], 1.0)
if len(errored) > 0:
print("connection errored, stopping")
break
if len(readables) > 0:
read_data = input_conn.recv(1024)
if len(read_data) == 0:
print("connection closed, stopping")
break
else:
print(f"read data: {read_data!r}")