Python C2服务器handleExit()函数异常,无法正常终止程序
C2服务器退出逻辑修复方案
问题描述
本人有C和Java开发背景,正在编写一个C2服务器学习Python网络编程与基础语法,不熟悉Python最佳实践。程序采用递归方式处理命令,需求是捕获CTRL+C或输入exit时终止程序并关闭套接字与线程,但执行后程序仍在后台运行,handleExit()函数无法正常工作。
核心问题点
- Python线程没有
stop()方法,该方法已被废弃,直接调用会报错 acceptClients线程是非守护线程,主线程退出后它会继续运行,导致程序残留后台serverSocket.accept()是阻塞调用,未处理时关闭socket无法立刻终止该阻塞handleExit中的资源关闭条件过于严格,需所有资源同时存在才执行关闭,导致部分场景下资源未释放- 捕获
KeyboardInterrupt时递归调用handleExit,可能引发输入流程异常
修复方案与代码实现
关键修改点
- 添加全局退出标志
running,用于控制线程循环 - 将
acceptThread设置为守护线程,主线程退出时自动终止 - 替换
while True为while running,通过标志位优雅终止线程 - 优化
handleExit的资源释放逻辑,逐个判断并关闭资源,不再依赖所有资源同时存在 - 移除
handleExit内的递归调用,改用循环处理用户确认输入 - 给
serverSocket设置超时,避免accept()永久阻塞
修复后完整代码
import socket import threading import sys from pyfiglet import figlet_format # 全局变量 serverSocket = None clientSocket = None acceptThread = None clientAddress = None running = True # 退出标志位 def handleInput(): i = input("SmoothArmy => ").lower() if i == "exit": handleExit() elif i == "help": helpCommand() elif i.startswith("listen"): # 处理可选端口参数 parts = i.split() port = int(parts[1]) if len(parts) > 1 else 9001 startListener(port) else: print("That command doesn't exist.") def helpCommand(): print("List of available Commands:\n") print("----------------------------------------------------------------------------------------\n") print("help : Shows available Commands\n") print("exit : To terminate session\n") print("listen <port> : Listen on a port\n") print("------------------------------------------------------------------------------------------\n") def startListener(port): global serverSocket global acceptThread try: if serverSocket is not None: print("Listener is already running.") return serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serverSocket.settimeout(1) # 设置超时,避免永久阻塞 serverSocket.bind(("", port)) # 绑定到所有网卡,而非仅本地主机 serverSocket.listen(10) print(f"listening on port {port}...") # 创建守护线程 acceptThread = threading.Thread(target=acceptClients, daemon=True) acceptThread.start() except Exception as e: print(f"There was an error starting socket: {e}") serverSocket = None def acceptClients(): global clientSocket global clientAddress while running: try: clientSocket, clientAddress = serverSocket.accept() print(f"Connection from {clientAddress} has been established!") except socket.timeout: continue # 超时后继续循环检查running标志 except Exception as e: if running: print(f"Accept error: {e}") break def handleExit(): global running while True: try: i = input("\nDo you want to exit? (y|n) ").lower() if i == "y": running = False # 设置退出标志 # 关闭客户端套接字 if clientSocket is not None: try: clientSocket.shutdown(socket.SHUT_RDWR) clientSocket.close() except Exception: pass clientSocket = None # 关闭服务器套接字 if serverSocket is not None: try: serverSocket.close() except Exception: pass serverSocket = None # 等待线程结束(可选,因线程是守护线程,主线程退出会自动终止) if acceptThread is not None and acceptThread.is_alive(): acceptThread.join(timeout=1) sys.exit(0) elif i == "n": break else: print("Please enter y or n.") except KeyboardInterrupt: print("\nPlease confirm exit with y or n.") print(figlet_format("SmoothArmy", font="standard")) print(" __ ") print(" _(\ |@@|") print("(__/\__ \--/ ") print(" \___|----| | __") print(" \ }{ /\ )_ / _\\") print(" /\__/\ \__O (__") print(" (--/\--) \__/") print(" _)( )(_") print(" `---''---`") print("\n") while running: try: handleInput() except KeyboardInterrupt: print("\n") handleExit()
额外的Python最佳实践建议
- 尽量减少全局变量的使用,可将相关资源封装到类中(比如
C2Server类),更符合面向对象思想,也便于管理状态 - 异常处理应避免空
except,明确捕获具体异常类型,便于排查问题 input()在多线程环境下可能出现问题,若后续扩展功能,需考虑线程安全的输入处理
内容的提问来源于stack exchange,提问作者KaoDev
相关产品推荐
相关产品推荐

