BluetoothChat の問題と対策


多くの方は Bluetooth の通信には、BluetoothChat をベースにして使っていると思います。
Bluetooth の性能評価をしていたときに、通信抜けがあることに気がつきました。

問題と対策
BluetoothChatService から BluetoothChat に受信データを渡すときに、Handler を介していますが、この部分で、抜けが生じていています。
通常は、BluetoothChatService -> Handler -> BluetoothChat という流れで、受信データは直ちに処理されます。
受信データの到着する間隔に対して、BluetoothChat の処理が遅れると、Handler がキューイングされます。
このとき、BluetoothChatService で用意している受信バッファが1つしかないために、前のHandler のバッファの内容が、次の Handler のバッファの内容に上書きされます。
Handler のバッファは、値を保持するのではなく、アドレスポインタを保持しているようです。
対策としては、受信バッファを複数面にすればいいことになります。
20150310_bluetooth_problem

対策の効果
そこで、受信バッファの面数と、通信の誤り率を、測定してみました。
2台のAndroid端末を用意して、1台は受信したデータをそのまま送信するエコーバックに設定します。もう1台は、数字を1,2,3..と連続して送信して、受信したデータが1,2,3..と連続しているかを照合します。
20150310_bluetooth_system

送信する間隔を1msから100msまで変化させて、受信したデータの誤り率を測定します。
測定結果は、下図のようになりました。
送信間隔30ms以下では、受信バッファの面数により、顕著な違いがあることが分かります。
20150310_bluetooth_result

対策の考察
受信バッファの面数を増やす利点は、分かりましたが。
欠点はないでしょうか。
考えられのは、メモリの使用量です。
受信バッファ1面は、1024バイトなので、1KB強のメモリを使います。
Android 4.0以降では、アプリに使用できるメモリ量は 64MB です。
あまり気にしなくてよさそうです。

なお、実際の運用を考えると、通信で誤りを起こすのは、上記の部分だけではありません。
Bluetooth などの無線経路は不確かなものです。
誤りがあることを前提に、システム全体やアプリを設計すべきですね。

ソースコード
今回の検証に使用したアプリを Gitbhub に公開しています。

BluetoothChatService.java

// 追加
private static final int NUM_PLANE = 32;
// ここまで
...
private class ConnectedThread extends Thread {
    ...
    public void run() {
        // 追加
        byte[][] buffers = new byte[ NUM_PLANE ][ 1024 ];
        int plane = 0;
        // ここまで
        byte[] buffer = new byte[1024];
        int bytes;
        while (true) {
            try {
                // 追加
                buffer = buffers[ plane ];
                if ( plane >= NUM_PLANE ) {
                    plane = 0;
                }
                // ここまで
                bytes = mmInStream.read(buffer);
                mHandler.obtainMessage(
                    BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
                    .sendToTarget();
            }
            ... 

20150310_bluetooth_screenshot_2


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です