Python新手请教网络编程中的read阻塞问题如何解决

现有的情况是这样的,服务器向客户端发包,而客户端使用 python 的 urllib 或者 request,建立连接,然后定时读取收到的数据量,来统计服务器发包的速率。

通过读了一些文档,里面都提到说 socket 的 read(amt)和 recv(amt)虽然默认都是阻塞的模式,但是都是返回此刻可以读取的最大数量值,只有在无法读取数据时才阻塞。

但是问题来了,我在使用 read 的时候,发现不论 amt 设置的大小,read 将会阻塞在其中,直到准确读取到 amt 的数量,这和文档中说到的和我的要求不符合啊==

求助:这和文档中说到的一致么?我要如何做呢?


Python新手请教网络编程中的read阻塞问题如何解决

13 回复

自顶一下啊


这个问题很常见。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 了

回到顶部