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当前没有数据可读,整个程序会停在这里,直到有数据过来或者连接断开。
咱们模拟一下实际流程:
- 客户端连接后发送
name,服务端成功接收并打印这条消息。 - 服务端循环继续,再次遍历到这个客户端socket时,客户端正处于等待用户输入的状态(还没发新消息),此时
recv()会直接阻塞整个服务端的循环。 - 之后客户端输入消息并发送,但服务端还卡在之前的
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
相关产品推荐
相关产品推荐

