You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

蓝牙模块连接异常致程序阻塞:单线程解法合理性及替代方案探讨

蓝牙双向通信的线程使用合理性与优化方案

一、当前单线程方案的合理性分析

你的做法有一定实用性,但存在明显隐患:

  • 可取之处:把客户端/服务器逻辑放到单独线程中,确实能避免连接异常时阻塞主线程,外层的while True也能在连接断开后自动尝试重连,这部分逻辑是有效的。
  • 问题隐患:
    1. 异常处理不严谨:比如客户端connect失败时sock未初始化,except里调用sock.close()会触发新报错;服务器端如果在accept前出异常,client_sock.close()同样会报错。
    2. 收发逻辑串行阻塞:当前代码里recv和input是串行执行的,必须等收到对方消息才能输入发送内容,本质是半双工,没法做到真正的同时收发。
    3. 资源泄漏风险:每次重连都会创建新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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 11:10:40