Python新手请教网络编程中的read阻塞问题如何解决
现有的情况是这样的,服务器向客户端发包,而客户端使用 python 的 urllib 或者 request,建立连接,然后定时读取收到的数据量,来统计服务器发包的速率。
通过读了一些文档,里面都提到说 socket 的 read(amt)和 recv(amt)虽然默认都是阻塞的模式,但是都是返回此刻可以读取的最大数量值,只有在无法读取数据时才阻塞。
但是问题来了,我在使用 read 的时候,发现不论 amt 设置的大小,read 将会阻塞在其中,直到准确读取到 amt 的数量,这和文档中说到的和我的要求不符合啊==
求助:这和文档中说到的一致么?我要如何做呢?
Python新手请教网络编程中的read阻塞问题如何解决
自顶一下啊
这个问题很常见。read()阻塞是因为它默认会一直等待,直到读取到指定数量的数据或连接关闭。解决的核心思路是设置超时、使用非阻塞模式,或者更高效地使用select/poll/asyncio。
最直接的方法是给socket设置超时:
import socket
# 创建socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0) # 设置5秒超时
try:
sock.connect(('example.com', 80))
sock.send(b'GET / HTTP/1.0\r\n\r\n')
# 现在read会在5秒后超时
data = sock.recv(1024)
print(f"Received: {data}")
except socket.timeout:
print("读取超时了!")
finally:
sock.close()
如果你需要更细粒度的控制,可以用select:
import socket
import select
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('example.com', 80))
sock.send(b'GET / HTTP/1.0\r\n\r\n')
# 等待数据可读,最多等3秒
ready = select.select([sock], [], [], 3.0)
if ready[0]:
data = sock.recv(1024)
print(f"Got data: {data}")
else:
print("等不到数据")
sock.close()
对于现代Python,直接用asyncio的异步IO更省心:
import asyncio
async def fetch_data():
reader, writer = await asyncio.open_connection('example.com', 80)
writer.write(b'GET / HTTP/1.0\r\n\r\n')
try:
# 异步读取,不会阻塞整个程序
data = await asyncio.wait_for(reader.read(1024), timeout=3.0)
print(f"Async got: {data}")
except asyncio.TimeoutError:
print("异步读取超时")
writer.close()
asyncio.run(fetch_data())
简单说就是:要么设超时,要么用异步。
总结建议:根据场景选方案,简单超时够用,复杂场景上异步。
很急的求助啊,自顶
Note that there are no methods read() or write(); use recv() and send() without flags argument instead.
代码都没有的吗。。。
有可能是一次到达的数据的大小大于你的 amt
pm = urllib3.PoolManager()
r = pm.request(‘GET’, url_path, preload_content=False)
data_received = 0
start_time = time.time()
now = time.time()
last_time = time.time()
with open(output_file_name, ‘w’) as out_file:
while True:
data = r.read(120000)
if not data:
break
代码是这样的,我打算改成非阻塞的?会不会有用?
可能是 urllib3 的 read 要求读到指定数据吧, 可以直接用 socket 读的.
已经贴出来代码了
传输层的 read 和应用层的 read 不是一个东西,你应该直接用 socket
嗯,我准备直接用 socket 了
gevent

