Python TCP Socket单线程能否同时运行客户端与服务端实例
认知错误纠正
你之前的认知核心混淆了两个完全不同的场景:
- 单线程无法处理需要并发响应多IO事件的TCP业务(比如同时等待多个外部客户端连接、同时处理多个连接的收发请求)
- 单线程可以按串行顺序操作多个socket,完成本地回环连接与交互
你的误区本质是把「多IO并发场景下的单线程阻塞缺陷」当成了「单线程不允许同时存在服务端、客户端两类socket」。
示例运行的底层原理
我们先逐行拆解代码的执行逻辑,结合内核TCP栈的处理规则就很容易理解:
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR import time # 1. 创建服务端监听socket,绑定端口开启监听 # 这一步只是在内核中注册了一个处于LISTEN状态的socket,执行完直接返回,不会阻塞 SERV_SOCK = socket(AF_INET, SOCK_STREAM) SERV_SOCK.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) SERV_SOCK.bind(('localhost', 8888)) SERV_SOCK.listen() # 2. 创建客户端socket发起连接 # 内核会自动完成TCP三次握手:客户端发SYN -> 监听socket收到后回SYN+ACK -> 客户端回ACK # 三次握手完成后,这个连接会被存入监听socket的全连接队列,connect方法直接返回,不会阻塞 CLIENT_SOCK = socket(AF_INET, SOCK_STREAM) CLIENT_SOCK.connect(('localhost', 8888)) # 3. 调用accept获取连接 # 直接从全连接队列中取出已经完成握手的连接,返回对应的服务端通信socket,无阻塞 CLIENT_SOCK_SERV, ADDR = SERV_SOCK.accept() # 4. 后续收发完全是串行执行:先由服务端通信socket发、客户端socket收,再反过来 # 每一步都是等上一个IO操作完成后才执行下一个,不存在需要同时等待多个IO的情况,单线程完全可以处理 TIMESTR = time.ctime(time.time()) + "\n" CLIENT_SOCK_SERV.send(TIMESTR.encode('utf-8')) TIME_BYTES = CLIENT_SOCK.recv(1024) print(f"Current time: {TIME_BYTES.decode('utf-8')}") time.sleep(1) TIMESTR = time.ctime(time.time()) + "\n" CLIENT_SOCK.send(TIMESTR.encode('utf-8')) TIME_BYTES = CLIENT_SOCK_SERV.recv(1024) print(f"Current time: {TIME_BYTES.decode('utf-8')}")
另外从内核资源的角度看:TCP连接由源IP、源端口、目的IP、目的端口四元组唯一标识,示例中的三类socket四元组完全不冲突,内核可以独立处理所有socket的收发逻辑,和这些socket是不是属于同一个进程、同一个线程没有任何关系:
- 服务端监听socket:
(0.0.0.0, 8888, *, *),状态为LISTEN - 客户端通信socket:
(127.0.0.1, 随机端口, 127.0.0.1, 8888),状态为ESTABLISHED - 服务端通信socket:
(127.0.0.1, 8888, 127.0.0.1, 客户端随机端口),状态为ESTABLISHED
补充说明
通常我们说服务端和客户端不能放在同一个单线程程序里,是指实际业务场景下服务端需要持续监听新连接、同时处理已有连接的收发,这时候单线程如果阻塞在某一个IO操作上,整个程序都会卡住,无法处理其他业务。但你的示例没有并发IO需求,所有操作按顺序执行,自然可以正常运行。
内容的提问来源于stack exchange,提问作者ibarbylev
相关产品推荐
相关产品推荐

