蓝牙开发经验小结——蓝牙通讯
2017-12-05 15:43
417 查看
场景:控制端——普通手机;被控制端——XX设备(无屏幕、无法用户操作、有系统权限)
有关蓝牙通讯的文章,网上有很多,也有免费的开源代码下载,BluetoothChatService和BluetoothUtil是核心代码。(找不到源码的可以联系我的邮箱,欢迎交流)过多的实现细节,这里不会赘述,仅讲述一下我在开发过程中,遇到的问题及解决方案。
蓝牙通讯过程:蓝牙开启——找到设备——配对——建立蓝牙socket连接——通讯协议;然后,再搭建你的业务逻辑。该代码实现的蓝牙连接为1对1的模式,因此,当你发现控制端反复连不上XX设备时,请注意检查是否已有控制端连接到了你想控制的XX设备。
简单轻量地使用蓝牙socket收发,应该没有问题。我遇到的问题是数据包截断——当一次发送的数据长度超过1KB时,会自动截断。因此,当你需要一次发送较大数据量时,需要小心处理。
抛砖引玉,我的处理办法详述如下:
在发送端的处理:
接收端的处理:
该处理办法经过实际验证是可行的。
另外,使用指定mac的连接方式,作为client端通常是已知对端的蓝牙mac的,而若server端要知道client的蓝牙mac,可以在如下节点获取并做一下保存(AcceptThread中的run方法):
这份代码存在一些crash的bug,例如BluetoothChatService没有退出就直接关闭掉蓝牙会出现crash,因此最好注册蓝牙状态的广播监听,若收到“BluetoothAdapter.STATE_TURNING_OFF”的广播,就直接调用BluetoothChatService的stop方法,及时退出。
有关蓝牙通讯的文章,网上有很多,也有免费的开源代码下载,BluetoothChatService和BluetoothUtil是核心代码。(找不到源码的可以联系我的邮箱,欢迎交流)过多的实现细节,这里不会赘述,仅讲述一下我在开发过程中,遇到的问题及解决方案。
蓝牙通讯过程:蓝牙开启——找到设备——配对——建立蓝牙socket连接——通讯协议;然后,再搭建你的业务逻辑。该代码实现的蓝牙连接为1对1的模式,因此,当你发现控制端反复连不上XX设备时,请注意检查是否已有控制端连接到了你想控制的XX设备。
简单轻量地使用蓝牙socket收发,应该没有问题。我遇到的问题是数据包截断——当一次发送的数据长度超过1KB时,会自动截断。因此,当你需要一次发送较大数据量时,需要小心处理。
抛砖引玉,我的处理办法详述如下:
在发送端的处理:
private static String END_FLAG = "XVOaVb77FMYHyeTx";//采用16位随机数做结束标记符 public void sendMessage(String message) { // Check that we're actually connected before trying anything if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) { //Toast.makeText(App.getInstance(), R.string.not_connected, Toast.LENGTH_SHORT).show(); logd("not connected yet."); return; } //logd("send:"+message); // Check that there's actually something to send if (message.length() > 0) { // Get the message bytes and tell the BluetoothChatService to write StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(message).append(END_FLAG);//用结束符来标记,防止数据过长,导致控制端因数据截断而无法识别的问题 byte[] send = stringBuilder.toString().getBytes(); mChatService.write(send); } }
接收端的处理:
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) { logd("create ConnectedThread: " + socketType); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the BluetoothSocket input and output streams try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { logd("temp sockets not created"+e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { logd("BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; StringBuilder stringBuilder = new StringBuilder(); // Keep listening to the InputStream while connected while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); stringBuilder.append( new String(buffer, 0, bytes)); //logd("length="+stringBuilder.length()); if (stringBuilder.toString().contains(END_FLAG) && stringBuilder.toString().endsWith(END_FLAG)) { String[] msgs = stringBuilder.toString().split(END_FLAG); for (String s : msgs) { mHandler.obtainMessage(BluetoothUtil.MESSAGE_READ, bytes, -1, s).sendToTarget(); } stringBuilder = new StringBuilder(); } } catch (IOException e) { logd("disconnected"+e); connectionLost(); // Start the service over to restart listening mode BluetoothChatService.this.start(); break; } } }
该处理办法经过实际验证是可行的。
另外,使用指定mac的连接方式,作为client端通常是已知对端的蓝牙mac的,而若server端要知道client的蓝牙mac,可以在如下节点获取并做一下保存(AcceptThread中的run方法):
// Listen to the server socket if we're not connected while (mState != STATE_CONNECTED) { try { // This is a blocking call and will only return on a // successful connection or an exception socket = mmServerSocket.accept(); } catch (IOException e) { logd("Socket Type: " + mSocketType + "accept() failed"+e); break; } // If a connection was accepted if (socket != null) { synchronized (BluetoothChatService.this) { switch (mState) { case STATE_LISTEN: case STATE_CONNECTING: // Situation normal. Start the connected thread. clientDevie = socket.getRemoteDevice();//在这里可以做一下 4000 记录 logd("client device address :" + clientDevie.getAddress()); connected(socket, clientDevie, mSocketType); break; case STATE_NONE: case STATE_CONNECTED: // Either not ready or already connected. Terminate new socket. try { socket.close(); } catch (IOException e) { logd("Could not close unwanted socket"+e); } break; } } } }
这份代码存在一些crash的bug,例如BluetoothChatService没有退出就直接关闭掉蓝牙会出现crash,因此最好注册蓝牙状态的广播监听,若收到“BluetoothAdapter.STATE_TURNING_OFF”的广播,就直接调用BluetoothChatService的stop方法,及时退出。
相关文章推荐
- 蓝牙开发经验小结——自动文件传输(OBEX)
- 蓝牙开发经验小结——自动配对
- webrtc实现即时语音通讯开发小结(native)
- 开发经验小结(网络编程(2))---套接字选项
- Phonegap + HTML5 开发经验小结
- Android 蓝牙设备通讯的开发(配对/连接/传输数据)
- PDA开发经验小结 (转共享)
- 开发经验小结
- 给浙江杭州某猎头公司开发猎头行业软件.NET接口的经验小结分享
- 基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍
- 基于BootStrap Metronic开发框架经验小结【四】Bootstrap图标的提取和利用
- 基于BootStrap Metronic开发框架经验小结【六】对话框及提示框的处理和优化
- Android开发蓝牙与ble设备的通讯
- 基于PDIUSBD12的USB通讯开发的一些经验
- iOS开发之蓝牙通讯
- Android开发之BlueTooth--最简单的Andorid传统蓝牙通讯Demo
- wince应用层开发经验积累-蓝牙电话设计开发总结
- 基于BootStrap Metronic开发框架经验小结【二】列表分页处理和插件JSTree的使用
- Android 手机应用开发经验 之 通过Socket(TCP/IP)与PC通讯
- 软件合作开发:2012年年底给苏州工业园区某家软件企业实施C#.NET软件开发系统框架的经验小结