Android 蓝牙通信及自定义消息协议的解析和生成

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();

        Set<BluetoothDevice> pairedDevices = 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);
                }
            }
        }
    };

猜你喜欢

转载自blog.csdn.net/bauterujj/article/details/75094876