PyBluez中socket.send()设阻塞后仍不阻塞,蓝牙传输速度计时失效
解决PyBluez中send()计时不准的问题
嘿,我之前做蓝牙传输测试的时候也踩过这个一模一样的坑!你遇到的问题本质是socket的send()(哪怕是阻塞模式)根本不是等数据真正传完才返回——它只是把数据拷贝到系统内核的发送缓冲区就立刻结束了,剩下的传输工作是操作系统的蓝牙栈在后台默默完成的。所以你现在统计的只是“把数据丢给系统”的时间,完全不是真正的蓝牙链路传输耗时。
为什么setblocking(True)没用?
阻塞模式只是让send()在缓冲区满的时候停下来等,直到有空间能把数据写进去,但只要数据一进缓冲区,它就会返回。哪怕你设置了阻塞,也没法让它等数据真正传到对方设备。
靠谱的解决方案:让接收端发确认包
这是统计端到端传输耗时最准确的方式,毕竟只有对方真正收到数据了,计时才是有效的。流程很简单:
发送端(树莓派)代码示例
import time import bluetooth # 假设你已经通过RFCOMM建立了连接,conn是已连接的socket对象 test_data = b"your_large_test_payload_here" # 比如生成10MB测试数据:b"x"*10*1024*1024 data_length = len(test_data) # 先把数据长度发给接收端,让它知道要收多少 conn.sendall(str(data_length).encode()) # 开始计时 start_time = time.time() # 发送全部数据(sendall会自动循环send直到所有数据写入缓冲区) conn.sendall(test_data) # 等待接收端的确认消息 ack_response = conn.recv(1024) if ack_response == b"DATA_RECEIVED": end_time = time.time() elapsed = end_time - start_time speed = (data_length / 1024 / 1024) / elapsed # 转换为MB/s print(f"实际传输耗时: {elapsed:.4f}秒") print(f"蓝牙传输速度: {speed:.2f} MB/s")
接收端(手机)对应逻辑伪代码
import bluetooth # 假设已建立蓝牙socket连接 # 先接收数据长度 length_str = sock.recv(1024).decode() total_length = int(length_str) # 循环接收直到拿到全部数据 received_bytes = b"" while len(received_bytes) < total_length: chunk = sock.recv(1024) if not chunk: # 连接断开 break received_bytes += chunk # 确认数据接收完成,发送响应 sock.sendall(b"DATA_RECEIVED")
备选方案(如果没法改接收端)
如果暂时没法修改手机端的代码,你可以尝试调整socket的发送缓冲区大小,让它和你的测试数据大小一致。这样sendall()会被迫等待缓冲区中的数据被蓝牙栈发送出去,才能写入剩下的数据,计时会更接近真实传输时间,但还是不如确认包准确:
import bluetooth data = b"your_test_data" conn.setsockopt(bluetooth.SOL_SOCKET, bluetooth.SO_SNDBUF, len(data)) conn.setblocking(True) start = time.time() conn.sendall(data) # 这里可以加一个小的延迟,或者检查发送缓冲区的剩余字节(实现难度较高) end = time.time()
额外注意点
- 蓝牙传输受环境干扰很大,建议在无遮挡的近距离测试,并且多次取平均值
- 如果测试大文件,分块发送+每块确认的方式会更稳定
- 不同蓝牙版本(比如BLE vs 经典蓝牙)的传输速度差异极大,确认你用的是经典蓝牙RFCOMM
内容的提问来源于stack exchange,提问作者mnt
相关产品推荐
相关产品推荐

