Если я использую socket.makefile и затем закрываю файловый объект, а также нижележащий сокет, то последующие вызовы read
вызовут исключение, как я бы этого хотел.Например, следующий код работает так, как я ожидал:
import socket
from time import sleep
from threading import Thread
ADDR = ("localhost", 4321)
def listener(sock):
client,addr = sock.accept()
sleep(1)
client.close()
sock.close()
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(ADDR)
server_sock.listen(1)
Thread(target=listener, args=[server_sock]).start()
sock = socket.create_connection(ADDR)
f = sock.makefile("r+b", bufsize=0)
f.close()
sock.close()
f.read(8) # throws an exception, as I'd expect
Однако, если я сделаю вызов read
, пока файл / сокет все еще открыты, этот вызов заблокируется, и затем если я закрою сокет, метод чтения все равно не вернется.Фактически, он висит бесконечно, пока сокет не будет закрыт на другом конце.Следующий код демонстрирует это удручающее поведение:
import socket
from time import sleep
from threading import Thread
ADDR = ("localhost", 4321)
def reader(f):
print("about to read")
print("we read %r" % f.read(8))
print("finished reading")
def listener(sock):
client, addr = sock.accept()
sleep(3)
client.close()
sock.close()
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(ADDR)
server_sock.listen(1)
Thread(target=listener, args=[server_sock]).start()
sock = socket.create_connection(ADDR)
f = sock.makefile("r+b", bufsize=0)
Thread(target=reader, args=[f]).start()
sleep(1)
print("closing pseudo-file and socket")
f.close()
sock.close()
sleep(1)
print("we still haven't finished reading!")
Это серьезная проблема для меня, так как я хотел бы сделать блокирующий вызов на f.read
в потоке, но затем все еще иметь возможность закрытьсокет и поток вернется из этого вызова (возможно, вызвав исключение) и выйдет.Однако все, что происходит, это то, что вызов блокируется навсегда, пока другая сторона никогда не закроет сокет.
Таким образом, есть ли способ для Thread1
вызвать read
для файлового объекта, созданногоsocket.makefile
и затем Thread2
отключить сокет таким образом, что Thread1
прекратит блокировку при вызове read
?
РЕДАКТИРОВАТЬ: Я попытался переписатьмоя программа полностью использует gevent
и ее сокет и Гринлет подход к многопоточности, но моя программа все еще делает то же самое:
from gevent import sleep, socket, spawn
ADDR = ("localhost", 4321)
def reader(f):
print("about to read")
print("we read %r" % f.read(8))
print("finished reading")
def listener(sock):
client, addr = sock.accept()
sleep(3)
client.close()
sock.close()
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(ADDR)
server_sock.listen(1)
spawn(listener, server_sock)
sock = socket.create_connection(ADDR)
f = sock.makefile("r+b", bufsize=0)
spawn(reader, f)
sleep(1)
print("closing pseudo-file and socket")
f.close()
sock.close()
sleep(1)
print("we still haven't finished reading!")
sleep(2)
Я был удивлен, узнав, что даже при использовании gevent
сокетов, вызововread
будет блокироваться даже после закрытия основного сокета.Если нет способа предотвратить это, я, вероятно, просто должен принять удручающий ответ Томаса «это невозможно»: (