Android蓝牙套接字已关闭但仍可用于发送串行数据

时间:2017-11-08 05:59:00

标签: android multithreading sockets io bluetooth

所以我在运行pybluez rfcomm-server的配对的raspberry pi设备之间建立了一个串行连接。我已经将我的Android设备与Pi配对,然后整合了一个利用线程处理双向异步通信的蓝牙服务。大多数代码都是直接来自Android开发人员指南上的蓝牙套接字通信here和读取/写入套接字here

当我通过关闭套接字并关闭处理通信的线程手动断开Pi时,会出现问题。我可以重新连接,启动另一个线程,然后再次成功开始与Pi进行通信但这就是它变得奇怪的地方,IOExcpetions开始被抛出,而Logcat正在骚扰和呻吟,并且"发生了错误发送数据"。这个例外很明显,就像我之前说过的那样,Pi仍然乐于接收消息。我可以通过一次又一次地断开连接和重新连接来重复这一点。

通常我会耸耸肩继续前进,因为它的工作正常吗?但我不觉得应该抛出任何IOExceptions。

以下是一些代码:

(BtBus是我制作的基于RxJava的消息总线,所有消息都在后台线程上发送并在主线程上接收)

BluetoothService - connect()和disconnect()方法

public void connect(){
    if(btAdapter == null) {
        Log.e(TAG, "No bluetooth adapter available");
    }
    Set<BluetoothDevice> pairedDevices = btAdapter.getBondedDevices();

    if (pairedDevices.size() > 0) {
        // There are paired devices. Get the name and address of each paired device.
        for (BluetoothDevice device : pairedDevices) {
            if(device.getName().contains("raspberry")){
                pi = device;
                Log.d(TAG, "using paired device: " + pi.getName());
                break;
            }
        }
    }else {
        Log.d(TAG, "No BT devices paired");
    }
    if(pi != null) {
        if(btAdapter.isDiscovering())
            btAdapter.cancelDiscovery();
        Observable.fromCallable(this::connectSocket)
                .observeOn(Schedulers.io())
                .subscribeOn(Schedulers.io())
                .subscribe(socket -> {
                    if(socket != null){
                        try {
                            socket.connect();
                            Log.d(TAG, "Socked with device created, creating thread");
                            connectedThread = new ConnectedThread(socket);
                            Log.d(TAG, "Thread created, starting...");
                            connectedThread.start();
                            Log.d(TAG, "Thread Started");
                            isConnected = true;
                            BtBus.publish(new BtAction("CONNECTION_ESTABLISHED"));
                        }catch (IOException e) {
                            Log.d(TAG, "Unable to connect socket");
                            e.printStackTrace();
                        }
                    }
                });
    }

//disconnect
public void disconnect() {
    if(socket != null) {
        connectedThread.cancel();
    }
}
private BluetoothSocket connectSocket(){
    try {
        socket = pi.createInsecureRfcommSocketToServiceRecord(DEFAULT_UUID);
        return socket;
    }catch (IOException e){
        Log.d(TAG, "Failed to get service with Pi UUID");
        return null;
    }
}

ConnectedThread

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;
    private byte[] mmBuffer; // mmBuffer store for the stream

    private ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the input and output streams; using temp objects because
        // member streams are final.
        try {
            tmpIn = socket.getInputStream();
        } catch (IOException e) {
            Log.e(TAG, "Error occurred when creating input stream", e);
        }
        try {
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(TAG, "Error occurred when creating output stream", e);
        }
        mmInStream = tmpIn;
        mmOutStream = tmpOut;
        BtBus.subscribe(action -> {
           if(action instanceof BtAction){
               write(((BtAction) action).getAction().getBytes());
           }
        });
    }

    public void run() {
        mmBuffer = new byte[1024];
        int numBytes; // bytes returned from read()
        // Keep listening to the InputStream until an exception occurs.
        while (true) {
            try {
                // Read from the InputStream.
                numBytes = mmInStream.read(mmBuffer);
                // Send the obtained bytes to the UI activity.
                BtAction action = BtCommFilter.getActionType(mmBuffer);
                BtBus.publish(action);
            } catch (IOException e) {
                Log.d(TAG, "Input stream was disconnected", e);
                break;
            }
        }
    }

    // Call this from the main activity to send data to the remote device.
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);
            // Share the sent message with the UI activity.
        } catch (IOException e) {
            Log.e(TAG, "Error occurred when sending data", e);
            // Send a failure message back to the activity.
        }
    }

    // Call this method from the main activity to shut down the connection.
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Could not close the connect socket", e);
        }
    }
}

这是来自异常

的堆栈相关堆栈跟踪
E/BluetoothService: Error occurred when sending data
java.io.IOException: socket closed
at android.net.LocalSocketImpl$SocketOutputStream.write(LocalSocketImpl.java:130)
at android.bluetooth.BluetoothSocket.write(BluetoothSocket.java:659)
at android.bluetooth.BluetoothOutputStream.write(BluetoothOutputStream.java:85)
at java.io.OutputStream.write(OutputStream.java:82)
at com.medspark.tenscontroller.service.BluetoothService$ConnectedThread.write(BluetoothService.java:183)
at com.medspark.tenscontroller.service.BluetoothService$ConnectedThread.lambda$new$0$BluetoothService$ConnectedThread(BluetoothService.java:157)
at com.medspark.tenscontroller.service.BluetoothService$ConnectedThread$$Lambda$0.accept(Unknown Source)
at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:60)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:200)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:252)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6872)      

正如您所看到的,当我关闭连接时,插座正确关闭并且线程被丢弃。当我重新连接时,创建了一个新的套接字并且新的线程被启动,所以我不知道抛出IOException的位置。提前谢谢。

0 个答案:

没有答案