Linux系统下USB蓝牙SPP服务端开发实战:从环境配置到数据通信
1. 环境准备从零搭建蓝牙开发环境第一次在Linux下折腾蓝牙开发时我对着满屏的命令行参数发懵。后来才发现其实只要搞定三个核心组件就能开工BlueZ蓝牙协议栈、USB蓝牙适配器驱动、基础开发工具链。这里分享下我验证过的配置方案。先检查你的USB蓝牙适配器是否被识别。插入设备后执行lsusb看到类似Cambridge Silicon Radio, Ltd Bluetooth Dongle的输出才算正常。如果设备未识别可能需要安装特定驱动。比如我用过的Realtek芯片适配器就需要额外固件wget https://raw.githubusercontent.com/Realtek-OpenSource/android_hardware_realtek/rtk1395/bt/rtkbt/Firmware/BT/rtl8723b_config wget https://raw.githubusercontent.com/Realtek-OpenSource/android_hardware_realtek/rtk1395/bt/rtkbt/Firmware/BT/rtl8723b_fw sudo mv rtl8723b_config /lib/firmware/rtl_bt/rtl8723b_config.bin sudo mv rtl8723b_fw /lib/firmware/rtl_bt/rtl8723b_fw.bin sudo modprobe btusb接下来安装BlueZ开发包。不同Linux发行版命令略有差异Ubuntu/Debian系sudo apt install bluez libbluetooth-devCentOS/RHEL系sudo yum install bluez bluez-libs-develArch Linuxsudo pacman -S bluez bluez-utils安装完成后建议立即修改蓝牙服务配置。新版BlueZ默认关闭了经典蓝牙的Socket支持需要手动开启兼容模式sudo sed -i s/ExecStart.*/ExecStart\/usr\/lib\/bluetooth\/bluetoothd -C/ /lib/systemd/system/bluetooth.service sudo systemctl daemon-reload sudo systemctl restart bluetooth2. SPP服务配置避开那些看不见的坑配置SPP服务时我踩过最深的坑就是SDP服务注册。网上教程都说执行sdptool add SP就行但实际可能会遇到Failed to connect to SDP server错误。这是因为BlueZ 5.x版本架构变化导致的需要分三步解决首先确认蓝牙控制器状态sudo hciconfig hci0 down sudo hciconfig hci0 reset sudo hciconfig hci0 up sudo hciconfig hci0 piscan然后处理服务通道冲突。执行sudo sdptool browse local查看已有服务如果显示过多服务超过5个需要手动删除部分sudo sdptool del 0x10001 # 删除指定句柄的服务最后注册SPP服务并验证sudo sdptool add --channel1 SP sudo sdptool browse local | grep Serial Port -A10成功时应该能看到类似输出Service Name: Serial Port Service RecHandle: 0x10005 Service Class ID List: Serial Port (0x1101) Protocol Descriptor List: L2CAP (0x0100) RFCOMM (0x0003) Channel: 13. 服务端代码实现从Socket到数据流核心代码其实就四步创建Socket-绑定通道-监听连接-处理数据。但每个环节都有细节要注意。这是我优化后的版本#include bluetooth/bluetooth.h #include bluetooth/rfcomm.h #define MAX_CLIENTS 5 int main() { struct sockaddr_rc loc_addr {0}, rem_addr {0}; char buf[1024] {0}; int sock, client, bytes_read; socklen_t opt sizeof(rem_addr); // 创建RFCOMM Socket if ((sock socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) 0) { perror(socket creation failed); exit(1); } // 绑定到通道1与sdptool配置一致 loc_addr.rc_family AF_BLUETOOTH; bacpy(loc_addr.rc_bdaddr, BDADDR_ANY); loc_addr.rc_channel 1; if (bind(sock, (struct sockaddr *)loc_addr, sizeof(loc_addr)) 0) { perror(bind failed); close(sock); exit(1); } // 开始监听 listen(sock, MAX_CLIENTS); printf(SPP Server listening on channel 1...\n); // 接受连接 client accept(sock, (struct sockaddr *)rem_addr, opt); if (client 0) { perror(accept failed); close(sock); exit(1); } ba2str(rem_addr.rc_bdaddr, buf); printf(Client connected from %s\n, buf); // 数据交互循环 while(1) { memset(buf, 0, sizeof(buf)); bytes_read read(client, buf, sizeof(buf)); if(bytes_read 0) { printf(Received: %s\n, buf); // 示例原样返回数据 write(client, buf, bytes_read); } else if(bytes_read 0) { printf(Client disconnected\n); break; } else { perror(read error); break; } } close(client); close(sock); return 0; }编译时需要链接蓝牙库gcc spp_server.c -o server -lbluetooth4. 实战调试那些手册没告诉你的经验地址字节序问题是最常见的连接失败原因。蓝牙地址格式是逆序存储的比如实际地址8C:88:2B:01:6E:17在代码中要写成17:6E:01:2B:88:8C。可以通过dmesg | grep -i blue查看实际连接尝试使用的地址。大数据传输测试时我发现直接发送16MB数据会导致缓冲区溢出。后来改用分块传输方案#define CHUNK_SIZE 4096 char data[CHUNK_SIZE]; size_t total_sent 0; while(total_sent total_size) { size_t to_send MIN(CHUNK_SIZE, total_size - total_sent); ssize_t sent write(client, data, to_send); if(sent 0) break; total_sent sent; }ARM平台适配需要特别注意两点交叉编译时确保使用目标平台的bluetooth.h头文件某些开发板如NVIDIA Jetson的蓝牙服务配置文件路径不同sudo vim /lib/systemd/system/bluetooth.service.d/nv-bluetooth-service.conf最后推荐几个调试命令bluetoothctl交互式管理蓝牙设备btmon实时监控蓝牙HCI流量hcitool底层控制工具rfcommRFCOMM通道管理
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2522041.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!