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

libusb_bulk_transfer传输接收数据过长 零长度包修复无效问题咨询

待解决的问题

我使用libusb_bulk_transfer通过USB传输数据,代码示例如下:

int sent = 0;
int bulk_result = libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, buffer,
                                       buffer_len, &sent, 5000);

另一端使用安卓平台的Kotlin代码接收传输数据。
大多数时候运行正常:比如发送289字节的缓冲区,接收端也会收到289字节。
但偶尔会出现接收数据量过大的问题:比如发送1536字节,实际收到1719字节。

我的无效修复方案

我查阅到的资料指出:「批量传输完成的判定条件为:传输了请求的 exact 数据量、传输了小于端点最大包长的数据包,或传输了零长度包」。
由于1536是64的倍数,且所有异常接收的数据包长度都是64的倍数,我判断问题源于此,因此计划在发送长度为端点最大包长整数倍的缓冲区后,追加发送一个零长度包。我也注意到端点最大包长不一定是64,因此做了动态获取处理。
我的「修复」代码如下:

int sent = 0;
int bulk_result = libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, buffer,
                                       buffer_len, &sent, 5000);

if (sent % get_usb_packet_size() == 0) {
  libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, nullptr, 0, &sent, 5000);
}

get_usb_packet_size()的实现如下,返回值为256:

int get_usb_packet_size() { return endpoint_out->wMaxPacketSize; }

但该方案并未生效:两次libusb_bulk_transfer的返回码都是0(成功),第一次调用上报发送了预期的buffer_len字节,第二次上报发送了0字节,均符合预期。
但接收端仍然会收到超出预期长度的数据包。我尝试把判断阈值换成64以发送更多零长度包,问题依旧存在。请问我遗漏了什么?


解答

你遗漏的核心问题包括以下几点:

  • 安卓端接收缓冲区复用问题:安卓USB bulkTransfer接收接口不会主动清空传入的缓冲区,如果你重复使用同一个字节数组接收数据,之前残留的旧数据会和新接收的数据混在一起,导致你统计到的长度超过实际接收长度。你需要每次调用接收接口前将缓冲区全部置零,接收后仅保留接口返回值长度的有效数据,不要统计整个缓冲区的大小。
  • 应用层缺少传输边界协议:仅靠USB底层的零长度包做边界不可靠,部分安卓底层驱动不会将零长度包作为前序传输的结束标记,反而会将其当作独立帧处理。你可以在应用层给每个传输块加固定长度的头部,比如前4字节存储本次传输的有效数据长度,接收端先读取头部拿到长度,再严格按照该长度读取后续数据,彻底规避底层传输边界的影响。
  • 零长度包发送逻辑有缺陷:你当前仅判断了实际发送字节数对包长取模为0的情况,但未校验sent是否等于本次要发送的buffer_len。如果出现短发送的情况,你追加的零长度包会被当作错误的边界标记,反而加剧数据错乱。需要先确认sent == buffer_len之后,再判断是否需要发送零长度包。
  • 安卓端接收参数不匹配:如果安卓端接收的超时参数设置过短,单次接收没拿到全量数据就返回,你如果把多次接收的结果直接拼接,也会出现长度超标的情况。可以先将安卓端接收超时设置和发送端的5000ms对齐,排除超时导致的多次接收拼接问题。

内容的提问来源于stack exchange,提问作者JonasVautherin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 05:45:09