8

アプリでBluetoothを使用すると問題が発生します。28 BluetoothSocket/BluetoothServerSocketsが作成された後、すべてのポートが取得されたようです。ソケットを同時に開く必要はありません。Bluetoothが有効になっているため、わずか28ソケットです。

これは、 Androidサンプルで提供されているBluetoothChatサンプルを使用して再現できます。アプリを15回開閉するだけです(アプリは毎回2つのソケットを作成します)。15回目にはクラッシュし、Bluetoothを無効にしてから再度有効にするまでクラッシュし続けます。

12-06 18:43:58.177: E/BluetoothSocket(18530): bindListen, fail to get port number, exception: java.io.IOException: read failed, socket might closed, read ret: -1
12-06 18:43:58.193: E/BluetoothChatService(18530): Socket Type: Insecurelisten() failed
12-06 18:43:58.193: E/BluetoothChatService(18530): java.io.IOException: Error: -1
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.bluetooth.BluetoothAdapter.createNewRfcommSocketAndRecord(BluetoothAdapter.java:1035)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.bluetooth.BluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(BluetoothAdapter.java:982)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at com.example.android.BluetoothChat.BluetoothChatService$AcceptThread.<init>(BluetoothChatService.java:280)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at com.example.android.BluetoothChat.BluetoothChatService.start(BluetoothChatService.java:119)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at com.example.android.BluetoothChat.BluetoothChat.onResume(BluetoothChat.java:131)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1185)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.Activity.performResume(Activity.java:5182)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2732)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2771)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2235)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.ActivityThread.access$600(ActivityThread.java:141)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.os.Handler.dispatchMessage(Handler.java:99)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.os.Looper.loop(Looper.java:137)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at android.app.ActivityThread.main(ActivityThread.java:5039)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at java.lang.reflect.Method.invokeNative(Native Method)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at java.lang.reflect.Method.invoke(Method.java:511)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
12-06 18:43:58.193: E/BluetoothChatService(18530):  at dalvik.system.NativeStart.main(Native Method)

ソケットを閉じた後にポートを解放する方法はありますか?

4

3 に答える 3

7

ここにあるデバイスでこの動作を確認できます。同じようにクラッシュするのに必要な回数はデバイスによって異なりますが(4.2を実行しているGalaxy Nexusでは20〜25回必要だったと思います)、使用可能なポートハンドルの数は異なるようです。BluetoothSocketまた、すべてのインスタンスがDalvikによってリリースおよびクローズされているため、問題がサンプルアプリ(またはそのことについてはアプリ)のメモリリークではないという情報を提供することもできます。ここにリストされている手順は、の問題をテストするだけBluetoothServerSocketなので、問題が特にそれに関連しているかどうかは不明ですが、可能性は低いようです。

少なくとも私のデバイスでは、Bluetoothアダプターのステータスを切り替えるまでアプリを再起動することさえできないため、問題は間違いなくスタック上の接続の基本的な管理にあります。

ここhttp://b.android.comで再現する手順を含むバグを報告し、喜んで賛成します。

于 2012-12-07T18:59:44.090 に答える
0

最近、私はこれに対する解決策を考え出すことを掘り下げなければなりませんでした。Androidのアップグレードはオプションではありませんでした。

接続が確立/切断されるたびにmAcceptThreadを破棄して再作成するのではなく、元のインスタンスを保持して再利用する場合がわかります。これにより、アプリへのバグの影響が最小限に抑えられます。

BluetoothChatServiceファイルのconnected()関数で、mAcceptThreadをキャンセルしないでください。

public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
...
...
...
// Cancel the accept thread because we only want to connect to one device 
//(Rather stay listening so comment out the cancel line!!) 
//If necessary, use some other state to prevent a second connection.
//DONT CANCEL: if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
...
...

AcceptThreadクラスで、run()関数のループを変更します。

            // Listen to the server socket if we're not connected
//OLD LOOP:            while (mState != STATE_CONNECTED)
//(Rather use STATE_NONE so the loop will only stop when the service does)
            while (mState != STATE_NONE) 

アイデアを適切に実装するために、コードで他にやるべきことがあるかもしれません。

于 2014-09-17T22:49:48.147 に答える
0

再接続するには、フラグメントの時限ハンドラーで使用します。

BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(MainActivity.mac);
                    // Attempt to connect to the device
                    mChatService.connect(device, true);

「28回以上再接続すると失敗する」という問題を解決するために、接続が失われたときにサービスが再起動するたびにコメントしました。

//BluetoothChatService.this.start();

また、ソケットが閉じるすべての部分をコメントアウトしました。

//socket.close();

//mmServerSocket.close();

//mmSocket.close();

//mSecureAcceptThread.cancel();

そして、acceptスレッドのnot null検出を追加し、失敗しないようにtheadを接続しました。

if(mAdapter != null) {
                        tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
                                MY_UUID_SECURE);
                    }else{
                        mAdapter = BluetoothAdapter.getDefaultAdapter();
                        //mState = STATE_NONE;
                    }

if(mmServerSocket != null) {
                        socket = mmServerSocket.accept();
                    }

それでもランダムな接続ドロップが発生しますが、サービスが再接続され、すべてが機能します。

于 2015-02-06T18:13:27.280 に答える