Windows 10环境下如何通过键盘中断(Ctrl+C)或编程方式关闭Python Socket服务器?
解决Windows下Python Socket服务器无法通过Ctrl+C中断的问题
我之前在Windows上也碰到过一模一样的问题!核心原因是**socket.accept()是阻塞调用**,在Windows系统里,阻塞的socket调用不会响应信号——程序一直卡在accept()那里,根本没机会执行你写的信号处理逻辑,自然没法用Ctrl+C中断。
下面给你两个亲测有效的解决方案:
方案1:给监听Socket设置超时,让循环有机会检查中断信号
给监听Socket加个短超时,这样accept()会定期抛出超时异常,我们就能在异常处理里检查是否收到中断信号,实现优雅退出:
import socket import sys import signal # 全局标志,标记是否需要退出服务器 shutdown_flag = False def signal_handler(signal, frame): global shutdown_flag print("\n收到中断信号,正在关闭服务器...") shutdown_flag = True # 注册SIGINT信号处理函数 signal.signal(signal.SIGINT, signal_handler) host = "127.0.0.1" port = 9001 # 初始化Socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((host, port)) s.listen(5) # 设置1秒超时,让accept()定期跳出阻塞 s.settimeout(1) print(f"服务器启动,监听 {host}:{port},按Ctrl+C关闭") try: while not shutdown_flag: try: # 尝试接受客户端连接 conn, addr = s.accept() print(f"新连接来自 {addr}") # 处理客户端请求 data = conn.recv(1024).decode() if data: print(f"收到数据:{data}") conn.send("Test message from server".encode()) conn.close() except socket.timeout: # 超时啥也不用做,只是让循环继续检查shutdown_flag continue finally: # 不管程序如何退出,最后都要关闭监听Socket print("关闭服务器Socket") s.close() sys.exit(0)
方案2:用线程拆分逻辑,主线程专门监听信号
把accept()和客户端处理放到子线程里,主线程只负责监听信号,这样信号一来就能立即响应:
import socket import sys import signal import threading def handle_client(conn, addr): """处理单个客户端连接的函数""" print(f"新连接来自 {addr}") data = conn.recv(1024).decode() if data: print(f"收到数据:{data}") conn.send("Test message from server".encode()) conn.close() def server_listen(s): """子线程中运行的监听逻辑""" while True: try: conn, addr = s.accept() # 每个客户端连接开一个守护线程处理 client_thread = threading.Thread(target=handle_client, args=(conn, addr)) client_thread.daemon = True client_thread.start() except Exception: # 服务器关闭时,accept会抛出异常,直接退出循环 break def signal_handler(signal, frame): """信号处理函数""" print("\n收到中断信号,正在关闭服务器...") s.shutdown(socket.SHUT_RDWR) s.close() sys.exit(0) host = "127.0.0.1" port = 9001 # 初始化Socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((host, port)) s.listen(5) # 注册信号处理 signal.signal(signal.SIGINT, signal_handler) print(f"服务器启动,监听 {host}:{port},按Ctrl+C关闭") # 启动监听线程 listen_thread = threading.Thread(target=server_listen, args=(s,)) listen_thread.daemon = True listen_thread.start() # 主线程阻塞等待,直到收到信号 listen_thread.join()
为什么你的原代码无效?
在Windows系统中,当程序卡在accept()这类阻塞式系统调用时,操作系统不会唤醒阻塞的线程去处理信号——你的程序根本到不了循环里的信号处理逻辑,一直卡在accept()上,自然没法响应Ctrl+C。上面两个方案都是通过“打破阻塞”或者“拆分逻辑”的方式,让程序有机会处理中断信号。
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

