You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 2 Socket编程:recv仅收首条消息问题及select方案问询

为什么Python 2 Socket编程中,不用select()就只能接收客户端第一条消息?

这个问题我之前也碰到过,本质是阻塞式IO的顺序执行导致的循环阻塞,咱们一步步拆解来看:

原代码的问题所在

先看你最初的服务端循环逻辑:

while True:
    for s in client_sockets:
        if s is server_socket:
            client_socket, address = server_socket.accept()
            client_sockets.append(client_socket)
            print('Connection received.')
        else:
            data = s.recv(200)
            if data:
                print('Received: {}'.format(data.decode().strip()))
            else:
                client_sockets.remove(s)
                s.close()

这里的核心问题是recv()是阻塞式调用:当你调用s.recv(200)时,如果这个客户端socket当前没有数据可读,整个程序会停在这里,直到有数据过来或者连接断开。

咱们模拟一下实际流程:

  1. 客户端连接后发送name,服务端成功接收并打印这条消息。
  2. 服务端循环继续,再次遍历到这个客户端socket时,客户端正处于等待用户输入的状态(还没发新消息),此时recv()会直接阻塞整个服务端的循环。
  3. 之后客户端输入消息并发送,但服务端还卡在之前的recv()调用里,根本没机会处理新的消息——除非客户端重启连接(这时候服务端的recv()会收到空数据,关闭旧连接,才能处理新连接的消息)。

更糟的是,如果同时有多个客户端,只要其中一个客户端没发消息,服务端就会卡在这个客户端的recv()上,其他客户端的消息和新连接都无法处理。

为什么select()能解决问题

select.select()的核心作用是帮你监听多个socket的状态,它会阻塞直到至少有一个socket处于你关注的状态(这里是「可读」),然后返回这些就绪的socket列表:

readable, writable, errored = select.select(client_sockets, [], [])
for s in readable:
    if s is server_socket:
        # 处理新连接逻辑
        ...
    else:
        # 此时调用recv()肯定能拿到数据,不会阻塞
        data = s.recv(200)
        ...

这样一来,服务端只会在有数据可读的socket上调用recv(),不会因为某个客户端没发消息就卡住整个循环。当客户端发送后续消息时,这个socket会被select标记为「可读」,服务端就能及时处理,自然就能接收后续消息了。

另外补充一点:你的客户端代码里用ljust(num_space_pads, ' ')填充消息到200字符的逻辑,并不是问题的根源,只是原服务端的阻塞逻辑让它没机会处理后续的填充消息而已。


内容的提问来源于stack exchange,提问作者Sean Francis N. Ballais

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:03:04