文章目录
- [蓝牙 SDP 层详解](#蓝牙 SDP 层详解)
-
- [1. 概述](#1. 概述)
- [2. 核心作用](#2. 核心作用)
- [3. 架构模型](#3. 架构模型)
- [4. 核心概念](#4. 核心概念)
-
- [4.1 服务记录(Service Record)](#4.1 服务记录(Service Record))
- [4.2 数据元素(Data Element)](#4.2 数据元素(Data Element))
- [4.3 UUID(通用唯一标识符)](#4.3 UUID(通用唯一标识符))
- [5. 关键属性](#5. 关键属性)
- [6. 工作流程](#6. 工作流程)
-
- [步骤 1:建立 L2CAP 连接](#步骤 1:建立 L2CAP 连接)
- [步骤 2:服务搜索(Service Search)](#步骤 2:服务搜索(Service Search))
- [步骤 3:属性获取(Attribute Retrieval)](#步骤 3:属性获取(Attribute Retrieval))
- [步骤 4:断开连接](#步骤 4:断开连接)
- [7. PDU(协议数据单元)](#7. PDU(协议数据单元))
- [8. SDP 的局限性与演进](#8. SDP 的局限性与演进)
- [9. 实际应用场景](#9. 实际应用场景)
- [10. 总结](#10. 总结)
蓝牙 SDP 层详解
1. 概述
SDP(Service Discovery Protocol,服务发现协议) 是蓝牙协议栈中位于 L2CAP 层之上 的核心协议之一,负责让蓝牙设备能够发现附近设备提供的服务及其属性,而无需事先了解对方设备的具体功能。
协议栈位置 :
应用层 / Profile → SDP → L2CAP → HCI → 基带 / 射频
2. 核心作用
| 功能 | 说明 |
|---|---|
| 服务发现 | 查询对端设备支持哪些蓝牙服务(如 A2DP、HFP、SPP 等) |
| 属性获取 | 获取服务的详细属性(如协议版本、通道号、服务名称等) |
| 动态适配 | 无需预配置,设备可动态发现并使用对端服务 |
3. 架构模型
SDP 采用 客户端-服务器(Client-Server) 架构:
┌─────────────┐ ┌─────────────┐
│ SDP Client │ ←──── L2CAP ────→ │ SDP Server │
│ (查询方) │ (PSM = 0x0001) │ (提供方) │
└─────────────┘ └─────────────┘
- SDP Server :驻留在提供服务的设备上,维护一张 服务记录表(Service Record)
- SDP Client:通过发送请求查询对端的服务信息
4. 核心概念
4.1 服务记录(Service Record)
每个服务对应一条记录,由多个 属性(Attribute) 组成,用 32位属性ID 标识。
4.2 数据元素(Data Element)
SDP 使用统一的数据编码格式表示所有数据,基本类型包括:
| 类型描述符 | 含义 |
|---|---|
0x00 |
Nil(空) |
0x01~0x08 |
无符号/有符号整数(1~8字节) |
0x09~0x10 |
UUID(16/32/128位) |
0x25 |
文本字符串 |
0x35 |
数据元素序列(Sequence) |
0x36 |
数据元素替代(Alternative) |
4.3 UUID(通用唯一标识符)
用于唯一标识服务类型或协议:
- 16-bit UUID :蓝牙 SIG 定义的标准服务(如
0x1101= SPP) - 32-bit UUID:扩展标准服务
- 128-bit UUID:自定义服务
5. 关键属性
| 属性 ID | 属性名 | 说明 |
|---|---|---|
0x0000 |
ServiceRecordHandle | 记录句柄,唯一标识一条服务记录 |
0x0001 |
ServiceClassIDList | 服务类别 UUID 列表 |
0x0002 |
ServiceRecordState | 记录状态(用于缓存判断) |
0x0003 |
ServiceID | 服务唯一标识 UUID |
0x0004 |
ProtocolDescriptorList | 协议描述符列表(含 PSM/Channel 等关键信息) |
0x0005 |
BrowseGroupList | 浏览分组列表 |
0x0006 |
LanguageBaseAttributeIDList | 语言基础属性偏移 |
0x0009 |
BluetoothProfileDescriptorList | Profile 描述符列表 |
0x0100 |
ServiceName | 服务名称 |
0x0101 |
ServiceDescription | 服务描述 |
重点 :
ProtocolDescriptorList(0x0004)通常包含 RFCOMM Channel 或 L2CAP PSM,是建立上层连接的关键。
6. 工作流程
步骤 1:建立 L2CAP 连接
SDP 使用固定的 PSM = 0x0001,通过 L2CAP 建立面向连接的通道。
步骤 2:服务搜索(Service Search)
Client 发送 SDP_ServiceSearchRequest ,携带目标 UUID ,Server 返回匹配记录的 Handle 列表。
Client → Server: Search for UUID = 0x1101 (SPP)
Server → Client: Handles = [0x00010001, 0x00010002]
步骤 3:属性获取(Attribute Retrieval)
Client 发送 SDP_ServiceAttributeRequest 或 SDP_ServiceSearchAttributeRequest,获取指定记录的详细属性。
Client → Server: Get attributes for Handle 0x00010001
Server → Client: ProtocolDescriptorList = [L2CAP, RFCOMM, Channel=3]
步骤 4:断开连接
获取所需信息后,关闭 L2CAP 通道。
7. PDU(协议数据单元)
| PDU 名称 | 用途 |
|---|---|
SDP_ErrorResponse |
错误响应 |
SDP_ServiceSearchRequest/Response |
搜索服务 |
SDP_ServiceAttributeRequest/Response |
获取指定记录的属性 |
SDP_ServiceSearchAttributeRequest/Response |
搜索并获取属性(合并操作) |
提示 :
ServiceSearchAttribute是最常用的组合操作,可在一个请求中完成搜索+属性获取。
8. SDP 的局限性与演进
| 局限 | 说明 |
|---|---|
| 仅发现,不连接 | SDP 只负责"发现",实际连接需上层协议(如 RFCOMM)完成 |
| 无安全机制 | SDP 本身不提供认证/加密,依赖蓝牙配对链路 |
| 查询效率低 | 传统蓝牙中需多次交互才能获取完整信息 |
| BLE 替代方案 | 低功耗蓝牙(BLE)使用 GATT(Generic Attribute Profile) 替代 SDP,基于 UUID 的属性表更高效 |
9. 实际应用场景
场景:手机连接蓝牙耳机
├─ 手机(SDP Client)查询耳机(SDP Server)
├─ 发现耳机支持 HFP(0x111E)和 A2DP(0x110D)
├─ 获取 HFP 的 RFCOMM Channel = 2
├─ 获取 A2DP 的 L2CAP PSM = 0x0019
└─ 手机分别建立 HFP 和 A2DP 连接
10. 总结
SDP 是蓝牙生态的**"目录系统"**,解决了设备间"你能做什么、怎么连接你"的问题。虽然其设计在经典蓝牙(BR/EDR)时代足够有效,但在 BLE 中已被更灵活的 GATT 所取代。理解 SDP 对于调试蓝牙连接问题、开发自定义 Profile 或分析协议抓包(如 Ellisys/Frontline)至关重要。