Socket通信几本协议:
首先解释下为什么Socket通信需要一定的协议才能理解消息的内容
1. 安全性, 协议中有判断内容安全的字段(比如报文的长度), 这样可以进行验证,如果被网络连接和篡改,这样的消息就是不安全的,不予处理
2. Socket通信, 消息达到一定的长度会分多次接收, 用协议的方式可以可以解决报文被截断的问题
3. 其他可能的原因
另外Socket在客户端一般用阻塞模式, 在服务器主动关闭时, 客户端会读取到-1长度的值, 此时会主动抛出异常
Socket服务器用的非阻塞模式
消息协议的封装方法:
public class ProtocolUtil { public static String bluetoothString(String content) { String data = null; String msgtype = "C"; data = String.format("%06x", calculatePlaces(msgtype)); data += msgtype; data += String.format("%06x", calculatePlaces(content)); data += content; data = String.format("%06x", calculatePlaces(data) + 1) + data; return data; } public static int calculatePlaces(String str) { int m = 0; char arr[] = str.toCharArray(); for (int i = 0; i < arr.length; i++) { char c = arr[i]; //中文字符 if ((c >= 0x0391 && c <= 0xFFE5)) { m = m + 3; } else if ((c >= 0x0000 && c <= 0x00FF)) { //英文字符 m = m + 1; } } return m; } }
消息协议的解析方法:
// 接收完后
String message = new String(bytes, "UTF-8");
// 消息总长度
int length = Integer.parseInt(message.substring(0, 6), 16);
// 消息类型
int typelen = Integer.parseInt( message.substring(6, 12), 16 );
String type = message.substring(12, 12 + typelen);
// 消息内容
int datalen = Integer.parseInt( message.substring(12 + typelen, 12 + typelen + 6), 16 );
String data = message.substring(18+typelen, message.length());
蓝牙通信步骤:
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // 开始搜索 private void startDiscovery() { if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } else {
// ListView适配器 mBluetoothDeviceAdapter.clear(); SetpairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices != null && pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo(device.getName() + "\n" + device.getAddress(), true); mBluetoothDeviceAdapter.addDevice(deviceInfo); } } else { BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo("No devices have been paired.", true); mBluetoothDeviceAdapter.addDevice(deviceInfo); } mBluetoothAdapter.startDiscovery(); } }
private final UUID socketUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private BluetoothServerSocket mServerSocket; private BluetoothSocket mSocket; private ReceiveThread receiveThread; private ServerThread serverThread; private ClientThread clientThread; private void startConnect(String address, boolean isServer) { if (isServer) { shutdownServer(); serverThread = new ServerThread(); serverThread.start(); } else { shutdownClient(); BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); clientThread = new ClientThread(device); clientThread.start(); } } // 停止服务器 private void shutdownServer() { if (serverThread != null) { serverThread.interrupt(); serverThread = null; } if (receiveThread != null) { receiveThread.interrupt(); receiveThread = null; } if (mSocket != null) { try { mSocket.close(); } catch (Exception e) { e.printStackTrace(); } mSocket = null; } if (mServerSocket != null) { try { mServerSocket.close(); } catch (Exception e) { e.printStackTrace(); } mServerSocket = null; } } // 停止客户端 private void shutdownClient() { // btExternalOpera.setText("等待连接"); if (clientThread != null) { clientThread.interrupt(); clientThread = null; } if (receiveThread != null) { receiveThread.interrupt(); receiveThread = null; } if (mSocket != null) { try { mSocket.close(); } catch (Exception e) { e.printStackTrace(); } mSocket = null; } }
// 停止接收消息 private void stopReceive() { if (receiveThread != null) { receiveThread.interrupt(); receiveThread = null; } } // 开始接收消息 private void startReceive() { stopReceive(); receiveThread = new ReceiveThread(); receiveThread.start(); } private class ServerThread extends Thread { @Override public void run() { try { mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM, socketUUID); mSocket = mServerSocket.accept(); startReceive(); } catch (Exception e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(ActivityDeviceControl.this, "未知异常!", Toast.LENGTH_SHORT).show(); } }); } } } // 启动客户端线程+读取消息 private class ClientThread extends Thread { private BluetoothDevice device; public ClientThread(BluetoothDevice device) { this.device = device; } @Override public void run() { InputStream readInput = null; try { runOnUiThread(new Runnable() { @Override public void run() { tv_connect_status.setText("连接中..."); } }); mSocket = this.device.createInsecureRfcommSocketToServiceRecord(socketUUID); mSocket.connect();// 无异常表示连接成功 receiveThread = new ReceiveThread(); receiveThread.start(); runOnUiThread(new Runnable() { @Override public void run() { statusCategory = STATUS_CATEGORY_BLUETOOTH; resetStatus(statusCategory); tv_connect_status.setText("已连接(" + device.getName() + ")!"); Prefs.putBluetoothAddress(ActivityDeviceControl.this, device.getAddress()); Toast.makeText(ActivityDeviceControl.this, "已连接到蓝牙!", Toast.LENGTH_SHORT).show(); } }); } catch (Exception e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { statusCategory = STATUS_CATEGORY_NET; resetStatus(statusCategory); tv_connect_status.setText("连接已断开!"); Toast.makeText(ActivityDeviceControl.this, "连接失败!", Toast.LENGTH_SHORT).show(); } }); } finally { if (readInput != null) { try { readInput.close(); } catch (Exception e) { e.printStackTrace(); } } } } } private class ReceiveThread extends Thread { @Override public void run() { InputStream readInput = null; try { // 限制在500字以内 byte[] buffer = new byte[1024]; int bytes;// 读取到的字节数 readInput = mSocket.getInputStream(); while (true) { if ((bytes = readInput.read(buffer)) > 0) { final String str = new String(buffer, 0, bytes); CLog.i(TAG, "receive:" + str); } } } catch (Exception e) { e.printStackTrace(); } finally {// 可能是服务器主动断开 if (readInput != null) { try { readInput.close(); } catch (Exception e) { e.printStackTrace(); } } shutdownClient(); } } } // The BroadcastReceiver that listens for discovered devices and // changes the title when discovery is finished private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // If it's already paired, skip it, because it's been listed already if (device.getBondState() != BluetoothDevice.BOND_BONDED) { BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo(device.getName() + "\n" + device.getAddress(), false); mBluetoothDeviceAdapter.addDevice(deviceInfo); } // When discovery is finished, change the Activity title } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { setProgressBarIndeterminateVisibility(false); if (mBluetoothDeviceAdapter.getCount() == 0) { BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo("没有发现蓝牙设备", false); mBluetoothDeviceAdapter.addDevice(deviceInfo); } } } };