关于libusb_interrupt_transfer超时与部分数据接收的技术咨询
LibUSB Interrupt Transfer Timeout & Partial Data Handling Questions(跨Linux/Windows场景)
问题描述
我正在开发一个能在Linux和Windows上运行的软件,使用libusb_interrupt_transfer从端点读取8字节数据时,碰到了LIBUSB_ERROR_TIMEOUT错误,有几个疑问想请教:
- 数据会被拆分吗?
- 文档提到接收数据时若
length未指定实际端点数据大小可能导致缓冲区溢出,同时超时需检查transferred变量(可能存在部分数据未接收),该如何处理部分接收的数据? - 若出现
LIBUSB_ERROR_TIMEOUT且数据包仅8字节,是否总能接收到全部8字节? - 若之前读取超时需补收2字节,是否始终要提供8字节缓冲区?
- 若提供8字节缓冲区但仅请求2字节,是否可能混入下一个数据包的6字节数据?
附上我的相关代码示例:
unsigned char data[8]; int timeout = 250; //timeout in milliseconds int xmtcnt = 0; int rcvcnt = 0; //EP OUT (Send data to USB Device) //0x02 = Endpoint Type 0x00 + Endpoint Number 2 r = libusb_interrupt_transfer(devh,0x02, data, sizeof(data), &xmtcnt, timeout); if(r != 0 || xmtcnt != 8){printf("XMT libusb_interrupt_transfer error %d\n",r); goto out_release;} //EP IN (Recv data from USB device) //0x81 = Endpoint Type 0x80 + Endpoint Number 1 //-----IS IT POSSIBLE TO RECEIVE LESS THAN 8 BYTES IF WE TIMEOUT?---- r = libusb_interrupt_transfer(devh,0x81, data, sizeof(data), &rcvcnt, timeout); if(r != 0 || rcvcnt != 8){printf("RCV libusb_interrupt_transfer error %d\n",r); goto out_release;} //show data received CONSOLE("data: %d %d %d %d %d %d %d %d xmt:%d rcv:%d\n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],xmtcnt,rcvcnt);
解答
1. 数据会被拆分吗?
没错,libusb确实可能根据底层系统的限制拆分传输。哪怕你要读的是8字节,底层说不定会拆成几次小传输来做——不过正常情况下这对你是透明的,只有超时的时候,这种拆分就会暴露出来,导致你只拿到部分数据。
2. 如何处理部分接收的数据?
当libusb_interrupt_transfer返回LIBUSB_ERROR_TIMEOUT时,一定要盯着transferred变量看,它会告诉你实际收到了多少字节。正确的处理方式应该是这样:
- 如果
transferred > 0,先把这部分数据存好,然后再发一次读取请求,把剩下的字节补回来(比如这次收了6字节,下次可以请求2字节,或者还是用8字节缓冲区,但自己记着还需要收多少)。 - 千万别直接把部分数据扔了!因为USB端点的接收队列是按顺序来的,没读完的部分会留在队列里,丢了的话后面的数据包就全错位了。
- 至于缓冲区溢出的问题:只要你的缓冲区大小是端点数据包大小的倍数,就不用担心溢出。要是不确定端点数据包多大,用libusb查一下设备描述符就行。
3. 出现超时且数据包仅8字节,是否总能接收到全部8字节?
真不一定。超时意味着在你设定的时间内没完成全部传输,有可能只收到一部分(比如系统刚读完3字节就到时间了)。这取决于系统调度快慢、设备响应速度这些不确定因素,所以绝对不能想当然认为超时后一定拿到完整8字节,必须检查transferred的值。
4. 若之前超时需补收2字节,是否始终要提供8字节缓冲区?
我建议你一直用和端点数据包大小匹配的缓冲区(也就是8字节)。原因有两个:
- USB设备是按端点的数据包大小发数据的(你这里是8字节),要是缓冲区太小,要么有溢出风险,要么会让数据拆分得更乱。
- 补收的时候,你可以在
libusb_interrupt_transfer的length参数里写要补的2字节,但缓冲区还是用8字节的,这样既安全,哪怕设备又发了完整8字节也能装下。后面只处理前2字节就行,剩下的空间不影响。
5. 提供8字节缓冲区但仅请求2字节,是否可能混入下一个数据包的6字节数据?
不会的。你请求读2字节,libusb就只会从端点拿最多2字节,剩下的6字节会留在设备的接收队列里,等你下次读的时候再拿。不过这种做法我不推荐——中断端点本来就是按固定数据包大小传输的,请求比数据包小的长度,不仅会降低底层处理效率,还会把你的数据处理逻辑搞复杂。最好还是按端点的数据包大小来发起读取请求。
内容的提问来源于stack exchange,提问作者12oclocker
相关产品推荐
相关产品推荐

