4. 经典蓝牙(BR/EDR)基础:设备发现、配对绑定、SDP与RFCOMM
各位同学,欢迎来到第四章。这一章我们聊聊经典蓝牙,也就是BR/EDR。说实话,很多新手一上来就被各种蓝牙协议搞懵了。我当年也一样,看着一堆英文缩写,头都大了。但别怕,咱们一步步来,把核心流程吃透。
经典蓝牙的核心,说白了就是四个步骤:发现设备 → 配对绑定 → 查询服务 → 建立通信。这就像你认识一个新朋友:先看到人(发现),然后交换名片(配对),接着了解对方会什么(SDP),最后才能愉快地聊天(RFCOMM)。
4.1 设备发现流程
设备发现,就是让蓝牙设备互相“看见”。在经典蓝牙里,这个过程叫 Inquiry(查询)。我刚开始做项目时,以为设备发现就是简单扫一下,结果发现坑不少。
流程其实不复杂:
- 查询设备(Inquiry):发起方广播查询请求,周围设备响应自己的地址和时钟信息。
- 可发现模式(Discoverable Mode):被发现的设备必须处于可发现模式,否则“隐身”。
- 查询扫描(Inquiry Scan):设备周期性监听查询请求,收到后回复。
我个人习惯在代码里设置一个 12秒 的发现超时。为什么是12秒?因为蓝牙规范里,一次完整的 Inquiry 周期大约需要 10.24 秒。留点余量,避免因为丢包导致发现不完整。
4.2 配对与绑定机制
找到设备之后,下一步就是配对。这里有个概念必须分清:配对(Pairing) 和 绑定(Bonding) 不是一回事。
| 概念 | 说明 | 是否存储密钥 |
|---|---|---|
| 配对 | 临时建立安全连接,断开后不保留密钥 | ❌ 否 |
| 绑定 | 配对后保存密钥,下次连接自动恢复 | ✅ 是 |
说白了,配对是一次性的,绑定是永久的。你手机连蓝牙耳机,第一次要输入PIN码,以后打开就能连——这就是绑定在起作用。
经典蓝牙的配对方式主要有三种:
- Legacy Pairing(传统配对):使用PIN码,安全性较低。老设备常用。
- Secure Simple Pairing(SSP,安全简单配对):蓝牙2.1引入,支持Numeric Comparison、Passkey Entry、Just Works等模式。
- Secure Connections(安全连接):蓝牙4.2引入,使用ECDH密钥交换,安全性更高。
4.3 服务发现协议(SDP)
配对完成后,你以为就能直接通信了?别急。你还需要知道对方能提供什么服务。这就是 SDP(Service Discovery Protocol) 的活。
SDP 的作用很简单:查询远程设备上有什么服务,以及如何访问这些服务。每个服务都有一个唯一的 UUID 来标识。
举个例子:
- 串口服务(SPP)的 UUID 是
00001101-0000-1000-8000-00805F9B34FB - 文件传输服务的 UUID 是
00001106-0000-1000-8000-00805F9B34FB
在 Android 中,我们通常这样查询服务:
// 获取远程设备的 SDP 记录
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
// 查询 SPP 服务
UUID sppUuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
Method method = device.getClass().getMethod("createRfcommSocketToServiceRecord", UUID.class);
BluetoothSocket socket = (BluetoothSocket) method.invoke(device, sppUuid);
嗯,这里要注意:SDP 查询是同步操作,不要在 UI 线程里执行。我习惯用 AsyncTask 或者协程来处理,避免 ANR。
4.4 RFCOMM 通信原理
终于到了通信环节。RFCOMM(Radio Frequency Communication) 是经典蓝牙最常用的串口模拟协议。它模拟了 RS-232 串口,让上层应用感觉就像在操作一个串口设备。
RFCOMM 的特点:
- 基于 L2CAP 协议,提供可靠的数据传输。
- 支持多路复用,一个物理通道可以承载多个 RFCOMM 会话。
- 最大数据包长度通常为 1024 字节(但可以协商)。
在 Android 中,RFCOMM 通信的典型流程是:
- 客户端调用
createRfcommSocketToServiceRecord()创建 Socket。 - 调用
connect()发起连接。 - 连接成功后,通过
InputStream和OutputStream读写数据。 - 通信结束后,关闭 Socket 释放资源。
我做过一个项目,需要同时传输音频和控制指令。当时我用了两个 RFCOMM 通道:一个传音频流,一个传控制指令。这样互不干扰,调试起来也方便。
HandlerThread。另外,记得处理 IOException,蓝牙连接随时可能断开。
最后,总结一下这一章的核心:
- 设备发现:找到设备,获取基本信息。
- 配对绑定:建立安全关系,区分临时和永久。
- SDP:查询服务,找到正确的通信入口。
- RFCOMM:模拟串口,实现可靠数据传输。
这四个步骤环环相扣,缺一不可。你想想看,如果跳过 SDP 直接连,你连对方用什么协议都不知道,怎么通信?所以,老老实实按流程来,别偷懒。
好了,这一章就到这里。下一章我们会深入 RFCOMM 的实战编码,包括如何封装一个稳定的蓝牙通信库。到时候见。