gpt4 book ai didi

python - 为什么我的 socket.makefile 对象在关闭后仍然阻塞?

转载 作者:行者123 更新时间:2023-11-28 22:04:40 24 4
gpt4 key购买 nike

如果我使用 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 有没有什么方法可以调用 socket.makefile 创建的类文件对象的 read 然后有 Thread2 以导致 Thread1 停止阻塞其 read 调用的方式关闭套接字?

编辑:我尝试重写我的程序以完全使用 gevent 及其套接字和 Greenlet 多线程方法,但我的程序仍然做同样的事情:

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 的调用也会在底层套接字关闭后阻塞。如果没有办法阻止这种情况,我可能只能接受 Thomas 令人沮丧的“这是不可能的”回答 :(

最佳答案

在这种情况下,我成功地使用了 eventlet现在,gevent正在做相同类型的事情:

“猴子修补”套接字库以使用非阻塞 I/O。以下是您可以尝试的示例:

>>> from gevent import monkey; monkey.patch_socket()
>>> import socket

看看这会如何影响你的结果

关于python - 为什么我的 socket.makefile 对象在关闭后仍然阻塞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6795500/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com