Python RFCOMM服务器与Android蓝牙连接适配问题求助
问题描述
使用Python 3的socket模块搭建蓝牙RFCOMM服务器,与Android设备连接时遇到两个问题:
- Android的
BluetoothDevice.createL2capChannel方法无法正常工作 - Android的
BluetoothDevice.createRfcommSocketToServiceRecord仅支持通过UUID连接,但Python的socket仅支持通过信道绑定
环境信息
- Python版本:3.11
- RFCOMM服务器系统:树莓派(Debian 12)
- Android版本:11
现有代码
Python服务器代码
from socket import * from threading import Thread class BluetoothService(Thread): def run(self) -> None: print("starting Bluetooth service...") s_sock = None try: s_sock = socket(family=AF_BLUETOOTH, type=SOCK_STREAM, proto=BTPROTO_RFCOMM) s_sock.bind(("D8:3A:DD:56:AF:08", 29)) s_sock.listen(1) c_sock, addr = s_sock.accept() print("client address:", addr) data = c_sock.recv(1) print(data) c_sock.close() finally: if s_sock is not None: s_sock.close() pass
Android端代码
val bthManger = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager val adapter = bthManger.adapter val device = adapter.getRemoteDevice("D8:3A:DD:56:AF:08") Log.i("Bluetooth", device.toString()) // checkPermission... val sock = device.createL2capChannel(29) sock.connect() sock.outputStream.write(100)
解决方案
方案1:Python服务器注册UUID服务(推荐)
Android的createRfcommSocketToServiceRecord是标准RFCOMM连接方式,需要服务器端注册对应的UUID服务,让Android设备能通过UUID发现并匹配到绑定的信道。
首先安装pybluez依赖:pip install pybluez,然后修改Python服务器代码:
from socket import * from threading import Thread import bluetooth class BluetoothService(Thread): # 通用串口服务UUID,也可以自定义唯一UUID SERVICE_UUID = "00001101-0000-1000-8000-00805F9B34FB" def run(self) -> None: print("starting Bluetooth service...") s_sock = None port = 29 try: # 注册SDP服务,关联UUID与信道 service_record = bluetooth.SDP_RECORD_CLASSIC_PORT(port, "Python RFCOMM Server") bluetooth.sdp_record_register(service_record, self.SERVICE_UUID) # 创建并绑定RFCOMM socket s_sock = socket(family=AF_BLUETOOTH, type=SOCK_STREAM, proto=BTPROTO_RFCOMM) s_sock.bind(("D8:3A:DD:56:AF:08", port)) s_sock.listen(1) print(f"Listening on RFCOMM channel {port} with UUID {self.SERVICE_UUID}") c_sock, addr = s_sock.accept() print("client address:", addr) data = c_sock.recv(1) print(data) c_sock.close() finally: # 注销SDP服务 bluetooth.sdp_record_unregister(self.SERVICE_UUID) if s_sock is not None: s_sock.close()
对应的Android端修改为UUID连接:
val bthManger = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager val adapter = bthManger.adapter val device = adapter.getRemoteDevice("D8:3A:DD:56:AF:08") Log.i("Bluetooth", device.toString()) // 检查BLUETOOTH_CONNECT等权限 val serviceUuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") // 与Python端UUID一致 val sock = device.createRfcommSocketToServiceRecord(serviceUuid) sock.connect() sock.outputStream.write(100)
方案2:Android端通过反射指定RFCOMM信道
若不想修改Python服务器,可通过Android反射调用底层API,直接指定RFCOMM信道连接:
val bthManger = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager val adapter = bthManger.adapter val device = adapter.getRemoteDevice("D8:3A:DD:56:AF:08") Log.i("Bluetooth", device.toString()) // 检查权限 val channel = 29 // 与Python服务器绑定的信道一致 var sock: BluetoothSocket? = null try { // 反射调用底层createRfcommSocket方法 val method = device.javaClass.getMethod("createRfcommSocket", Int::class.java) sock = method.invoke(device, channel) as BluetoothSocket sock.connect() sock.outputStream.write(100) } catch (e: Exception) { e.printStackTrace() } finally { sock?.close() }
注意:反射方法依赖Android系统底层实现,不同版本可能存在兼容性问题,Android 11下可正常使用。
补充说明
createL2capChannel无法工作是因为协议不匹配:你的Python服务器使用的是RFCOMM协议,而L2CAP是另一种独立的蓝牙协议,两者无法互通,并非方法本身失效。
内容的提问来源于stack exchange,提问作者朽木不可雕也
相关产品推荐
相关产品推荐

