【问题标题】:Android: BluetoothSocket receives its own outputAndroid:BluetoothSocket 接收自己的输出
【发布时间】:2018-09-22 09:44:58
【问题描述】:

我有一个应用程序,它通过蓝牙连接到 RaspberryPi,并在接收一些数据时将相同的数据循环给它。

我在连接时遇到了一些问题,因此需要使用此解决方法将我的 Android 手机连接到 RaspberryPi:IOException: read failed, socket might be closed - Bluetooth on Android 4.3

由于某种原因,android 手机正在接收自己的输出。 字符串 "Hello Raspberry. It's me, AndroidPhone" 以永无止境的循环发送到输出。传入的数据(来自 RaspberryPi)也在一个永无止境的循环中被读取。

但不知何故,我不仅接收来自 RaspberryPi 的数据,还接收通过智能手机发送的字符串。这是我的代码:

public class MainActivity extends AppCompatActivity {
    private BluetoothAdapter bluetoothAdapter;
    UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // (...)
        // Only GUI-stuff until this point

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        BluetoothDevice raspberryPi = bluetoothAdapter.getRemoteDevice("B8:27:EB:56:DC:B2");
        BluetoothSocket btSocket;

        try {
            btSocket = raspberryPi.createRfcommSocketToServiceRecord(SERIAL_UUID);
            btSocket.connect();
        } catch (IOException e) {
            Log.e("BTError", e.getMessage());
            // Workaround, found on: https://stackoverflow.com/questions/18657427/ioexception-read-failed-socket-might-closed-bluetooth-on-android-4-3
            try {
                Log.e("BTError", "Trying fallback...");
                btSocket = (BluetoothSocket) raspberryPi.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(raspberryPi, 1);
                btSocket.connect();

                (new Thread(new SendingThread(btSocket))).start();
                (new Thread(new ReceivingThread(btSocket))).start();
            } catch (Exception e2) {
                Log.e("BTError", e2.getMessage());
                Log.e("BTError", "Couldn't establish Bluetooth connection!");
            }
        }
    }

    private class SendingThread extends Thread {
        private OutputStream out;

        public SendingThread(BluetoothSocket btSocket) {
            try {
                out = btSocket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            try {
                int delay = 100000000;
                while (true) {
                    if (delay == 0) {
                        Log.i("WRT", "Written to RaspberryPi");
                        out.write("Hello Raspberry. It's me, AndroidPhone".getBytes());
                        delay = 100000000;
                    }
                    delay--;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private class ReceivingThread extends Thread {
        private InputStream in;

        public ReceivingThread(BluetoothSocket btSocket) {
            try {
                in = btSocket.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            int data = 0;
            while (true) {
                try {
                    data = in.read();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Log.i("RCV", String.valueOf((char) data));
            }
        }
    }

在 RaspberryPi 端,一切看起来都很正常。一个简单的 java 程序启动 Linux 命令rfcomm listen /dev/rfcomm0 并使用FileReaderFileWriter 读取/写入文件/dev/rfcomm0。唯一相关的行是:

run {
    // Inside writer-thread
    bluetoothWriter = new BufferedWriter(new FileWriter("/dev/rfcomm0"));
    while(true) {
        bluetoothWriter.write("This is RaspPi");
        bluetoothWriter.flush();
    }
}

run {
    // Inside reader-thread
    bluetoothReader = new BufferedReader(new FileReader("/dev/rfcomm0"));
    while(true) {
        int incData = bluetoothReader.read();
        System.out.print((char) incData);
    }
}

感谢您的帮助!

编辑: 仍然没有解决这个问题。我怀疑 RaspberryPi 以某种方式发回了它收到的东西。但是当我禁用它发送任何东西时,智能手机仍然直接接收它发送的东西。

【问题讨论】:

  • 你有没有尝试改变调用createRfcommSocket的反射方法的参数?它应该改变蓝牙套接字的通道,也许这就是问题所在。
  • 是的,我已经尝试更改 android 应用程序中使用的频道以及(只是为了完全确定)在 RaspberryPi 上运行的程序使用的频道。遗憾的是它并没有解决问题。
  • 您是否尝试过以 30 秒的间隔大幅减少发送,以便真正分析调试器内部的输出和输入?似乎有什么东西在回响。您是否尝试过在来自 rasberry pi 的输出写入消息中添加“我的 rasberry pi 前缀”前缀,以查看您是否在 rasberry pi 上有完整的消息?您还检查了输出和接收的字节十进制值,以比较到达 Rasberri Pi 的内容。我会对到达 rasberry pi 的内容以及“确切发送”的内容更感兴趣。
  • 我想说的是,您是否 100% 肯定您已经检查了离开 rasberri pi 的字节并确认它们不包含您的消息。因为如果他们这样做了,那么你的问题就不是 rasberri 方面,也不是 Android。

标签: java android bluetooth android-bluetooth


【解决方案1】:

我搜索了蓝牙类的资源。乍一看,解决方法似乎是合法的。先试试这个:

if (delay == 0) {
    Log.i("WRT", "Written to RaspberryPi");
    out.write("Hello Raspberry. It's me, AndroidPhone".getBytes());
    out.flush(); // <-- You are not flushing 
    delay = 100000000;
}

消息会留在您的套接字中,供您一遍又一遍地阅读。

如果这不能解决它,我能想到的另一个选项是,以某种方式将套接字初始化为您的 Android 设备的套接字。 .createRfcommSocket() 方法似乎会为您自己的设备创建一个套接字,如果在创建套接字时蓝牙设备是 null。我不确定这到底是怎么发生的,但是如果 Raspberry Pi 的状态在异常之后以某种方式被破坏,我想这可能是值得研究的事情。

raspy 方面:如果您只是启动这两个线程,这并不意味着您不断地向/dev/rfcomm0 发送消息并刷新。我建议您更改它,以便raspy 通过发回想要的消息而不是一直发送垃圾邮件来对收到的消息做出反应。我不确定这是否是您的问题的一部分,但它至少会使调试和开发更容易一些。

【讨论】:

    【解决方案2】:

    我不确定这是否是您需要的解决方案,因为我不知道您使用的是蓝牙经典版还是蓝牙 4.0>+,但我为基于文本的 BLE 和 WiFi P2P 2-way 写了一个library android 的通信(我知道 Raspberry Pi 能够进行 BLE 通信),虽然我没有为 BLE 通信创建套接字连接,但我为 WiFi P2P 做。看看吧,希望对你有帮助。它尚未发布,因此您必须克隆/分叉该 repo。

    【讨论】:

      【解决方案3】:

      我觉得你写作有问题
      据我所知,对于缓冲区,应该使用 \n 和 ...

      bluetoothWriter.write("This is RaspPi\n");
      

      但我更喜欢结合使用DataOutputStreamBufferedReader

      供阅读:

          BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
              try {
                String line = bufferedReader.readLine();
      System.out.println(line);
              } catch (IOException e) {
                e.printStackTrace();
              }
      

      写:

      DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
          String s = "Hi\n";
          try {
            dataOutputStream.write(s.getBytes());
          } catch (IOException e) {
            e.printStackTrace();
          }
      

      最好纠正一下亲爱的朋友关于flush()的观点……

      我不确定,请自行测试...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-26
        • 1970-01-01
        相关资源
        最近更新 更多