蓝牙模块连接异常致程序阻塞:单线程解法合理性及替代方案探讨
蓝牙双向通信的线程使用合理性与优化方案
一、当前单线程方案的合理性分析
你的做法有一定实用性,但存在明显隐患:
- 可取之处:把客户端/服务器逻辑放到单独线程中,确实能避免连接异常时阻塞主线程,外层的
while True也能在连接断开后自动尝试重连,这部分逻辑是有效的。 - 问题隐患:
- 异常处理不严谨:比如客户端
connect失败时sock未初始化,except里调用sock.close()会触发新报错;服务器端如果在accept前出异常,client_sock.close()同样会报错。 - 收发逻辑串行阻塞:当前代码里
recv和input是串行执行的,必须等收到对方消息才能输入发送内容,本质是半双工,没法做到真正的同时收发。 - 资源泄漏风险:每次重连都会创建新socket,若异常发生在特定位置,旧socket可能未被正确关闭,长期运行会消耗系统资源。
- 异常处理不严谨:比如客户端
二、更优解决方案
1. 拆分收发线程,实现真正全双工
把接收和发送逻辑拆成两个独立线程,互不阻塞,这是实现同时收发的核心改进方向。
修正后的客户端代码(中文注释)
import bluetooth import threading import time # 服务器蓝牙地址与端口 bd_addr = "00:e0:4c:9a:f8:64" port = 1 current_sock = None def recv_from_server(): global current_sock while True: if not current_sock: continue try: data = current_sock.recv(1024) if not data: # 对方断开连接 print("服务器已断开连接") current_sock.close() current_sock = None break print("收到服务器消息:", data.decode()) except Exception as e: print("接收出错:", str(e)) if current_sock: current_sock.close() current_sock = None break def send_to_server(): global current_sock while True: txt = input("输入要发送给服务器的内容: ") if not current_sock: print("未连接到服务器,请等待重连") continue try: current_sock.send(txt.encode()) except Exception as e: print("发送出错:", str(e)) if current_sock: current_sock.close() current_sock = None def client_connect(): global current_sock while True: try: if current_sock: continue print("尝试连接服务器...") sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) sock.connect((bd_addr, port)) current_sock = sock print("成功连接到服务器") except Exception as e: print("连接失败,5秒后重试:", str(e)) time.sleep(5) # 启动三个线程:连接维护、接收、发送 threading.Thread(target=client_connect, daemon=True).start() threading.Thread(target=recv_from_server, daemon=True).start() threading.Thread(target=send_to_server, daemon=True).start() # 让主线程保持运行 while True: time.sleep(1)
修正后的服务器端代码(中文注释)
import bluetooth import threading import time port = 1 current_client_sock = None def recv_from_client(): global current_client_sock while True: if not current_client_sock: continue try: data = current_client_sock.recv(1024) if not data: # 客户端断开 print("客户端已断开连接") current_client_sock.close() current_client_sock = None break print("收到客户端消息:", data.decode()) except Exception as e: print("接收出错:", str(e)) if current_client_sock: current_client_sock.close() current_client_sock = None break def send_to_client(): global current_client_sock while True: txt = input("输入要发送给客户端的内容: ") if not current_client_sock: print("无客户端连接,请等待") continue try: current_client_sock.send(txt.encode()) except Exception as e: print("发送出错:", str(e)) if current_client_sock: current_client_sock.close() current_client_sock = None def server_accept(): global current_client_sock server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) server_sock.bind(("", port)) server_sock.listen(1) print("服务器已启动,等待客户端连接...") while True: try: if current_client_sock: continue client_sock, address = server_sock.accept() print(f"已接受来自 {address} 的连接") current_client_sock = client_sock except Exception as e: print("连接接受出错:", str(e)) time.sleep(2) # 启动三个线程:监听连接、接收、发送 threading.Thread(target=server_accept, daemon=True).start() threading.Thread(target=recv_from_client, daemon=True).start() threading.Thread(target=send_to_client, daemon=True).start() # 主线程保持运行 while True: time.sleep(1)
2. 回调函数的适用场景
回调函数适合事件驱动的非阻塞IO场景,比如用Python标准库selectors实现单线程下的多socket监听,当socket有可读/可写事件时触发回调,无需创建多个线程。这种方式资源开销更低,但代码复杂度稍高,适合对系统资源占用有严格要求的场景。
三、核心优化点总结
- 拆分收发逻辑,真正实现全双工同时通信
- 完善异常处理,避免未初始化变量调用方法
- 增加连接状态管理,防止无效操作
- 可选:用事件驱动(回调)替代多线程,降低资源消耗
内容的提问来源于stack exchange,提问作者Purulence
相关产品推荐
相关产品推荐

