3. USB数据流模型

刚接触USB协议分析的时候,很多人第一反应就是盯着抓包窗口里的“STUFF”看。但是我跟你说,不搞清楚数据流模型,你抓出来的包就是一串乱码。

说白了,USB通信的核心就三个概念:端点(Endpoint)、管道(Pipe)和传输类型(Transfer Type)。这三者串起来,才构成了一条完整的数据流动通道。今天我就把这套模型掰开揉碎了讲清楚。

3.1 端点:USB设备里的“通信口袋”

每个USB设备内部都有若干个端点。你可以把端点想象成一个“收发信口”。每个端点都有一个固定的用途——有的专门接收数据,有的专门发送数据,还有的既能收也能发(控制端点)。

端点在硬件上由端点描述符定义。我习惯在项目中用USB分析仪先列出设备的所有端点描述符,看一眼就知道这个设备有几个“口袋”。

关键信息:端点编号范围0~15,每个端点有方向(IN/OUT)和类型。端点0是默认控制端点,每个设备必须有。

抓包的时候,你会看到每个包都有一个“端点地址”字段。比如 0x81,高4位是端点号(8),最低位1表示IN方向(Device→Host)。所以我常说:“看端点地址就能知道数据在往哪儿跑。”

端点地址格式 例子 含义
0x01 端点1 OUT Host→Device,发数据给设备
0x82 端点2 IN Device→Host,从设备读数据
0x00 端点0 CONTROL 双向控制通道,枚举必用

我曾经调试一个UVC摄像头,发现图像卡顿。抓包一看,端点的批量传输端点地址居然指向了OUT方向——摄像头不可能从主机拿图像数据。改完描述符就正常了。这种坑,端点地址看错一次就够了。

3.2 管道:端点与主机之间的“虚拟管线”

端点有了,谁负责把数据送过去?管道就是干这个的。管道是主机软件与设备端点之间的逻辑连接。它不占用物理线路,而是由USB控制器在内部维护的一条数据通道。

管道分两种:

  • 消息管道(Message Pipe):带格式的、双向的控制传输专用管道。必须走端点0,传输的是USB请求块(Setup包)加数据。
  • 流管道(Stream Pipe):无格式的、单向的数据流管道。用于批量、中断、同步传输,数据就是纯粹的荷载。

你在分析仪上看到的每个事务(Transaction),都会标记它属于哪个管道。我个人习惯先看管道方向,再对端点的类型,这样能快速判断这个包是不是正常的。

3.3 传输类型:四种“快递方式”

管道到底怎么跑数据?取决于传输类型。USB定义了四种,每种都有自己的应用场景。

3.3.1 控制传输

最基础的传输。每次传输包含三个阶段:Setup、Data(可选)、Status。所有设备的枚举和配置都靠它。我在项目里最常分析的抓包就是控制传输——你看一个USB设备能不能被主机识别,就看控制传输的流程顺不顺。

3.3.2 批量传输

数据量大,但允许偶尔重传。典型应用:U盘、打印机、UVC摄像头的数据流。批量传输能保证数据没错,但延时不确定。

3.3.3 中断传输

固定间隔轮询,适合人机交互设备(HID)。键盘、鼠标、游戏手柄都用它。它的特点:数据量小(最大64字节),必须保证每帧内都轮询。

3.3.4 同步传输

固定带宽、固定延时,但不保证重传。音频、视频流典型场景。你想想看,如果播放音乐时每丢一帧就重传一次,那声音早就卡到没法听了。同步传输就是“宁可丢帧,不可重传”。

抓包时怎么看传输类型?看令牌包里的PID。比如SETUP+DATA0+ACK——八成是控制传输。如果是OUT或IN后接着DATA0/1——批量或中断。如果连PID都不变,纯数据——同步传输。

3.4 四种传输类型对比

特性 控制传输 批量传输 中断传输 同步传输
典型应用 枚举、配置 U盘、打印机 键盘、鼠标 音频、视频
保证交付 是 是 是 否
保证带宽 否 否 是(固定间隔) 是(固定带宽)
最大包长(HS) 64字节 512字节 1024字节 1024字节
错误重试 支持 支持 支持 不支持

3.5 从抓包实战看数据流模型

嗯,这里要注意。你在分析仪里看到的每一帧,其实都在体现这个模型。

  1. 先看SOF(帧起始包)——确认USB总线处于活动状态。
  2. 接着看令牌包——里面包含了端点地址和方向。比如IN 0x81,表示主机想从端点1读数据。
  3. 再看数据包——就是实际传输的载荷。
  4. 最后握手包——ACK表示成功,NAK表示设备忙,STALL表示端点挂起。

我经常遇到的情况:某一次设备不响应,抓包发现端点返回的是STALL。查了一下描述符,原来是端点类型定义错了——该用中断的配成了批量,设备协议栈直接罢工。

所以,理解端点、管道、传输类型,不是死记硬背。你只要在分析仪上多看几次“端点地址+传输类型+握手包”,马上就能建立直觉。

USB数据流模型关系图 主机(Host) USB控制器 + 驱动 管道(Pipe) 消息管道 流管道 USB 设备 功能 + 端点 端点(Endpoint) 端点0 CONTROL 端点1 BULK 端点2 INT 端点3 ISO 4种传输类型 💡 每个端点对应一种传输类型 管道是主机与端点之间的逻辑连接 抓包时重点看端点地址和PID

3.6 实战避坑指南

最后分享几个我踩过的坑:

  • 端点地址别搞反方向:我曾经把一个批量IN端点的地址配成了0x01(OUT),结果主机死活读不到数据。分析仪上看到主机发IN令牌,设备没反应。查了一个小时,才发现描述符写错了。
  • 控制传输一定要等到Status阶段:有的初学者抓包只看到Setup和Data,以为结束了。其实后面还有一次IN/OUT的零长度包做握手指令,缺少这个,主机认为传输失败。
  • 中断传输的间隔不是固定的:虽然描述符里写了轮询间隔,但实际抓包会发现间隔浮动。我在调试一个无线鼠标时,发现主机没按1ms轮询,而是跳到了2ms——后来发现是总线拥挤,主机降低了优先级。

OK,这一章就到这里。记住:端着分析仪,先看端点,再查管道,最后确认传输类型。三步走,数据流模型就清清楚楚了。