Android:BluetoothSocket收到自己的输出

时间:2018-04-12 09:39:13

标签: java android io bluetooth stream

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

我遇到了一些连接问题,所以需要这个解决方法才能将我的Android手机连接到RaspberryPi:IOException: read failed, socket might closed - Bluetooth on Android 4.3

由于某种原因,Android手机正在接收自己的输出。 String " Hello Raspberry。它是我,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,并使用/dev/rfcomm0FileReader读取/写入文件FileWriter。这方面唯一相关的路线是:

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以某种方式发回了它收到的内容。但当我禁用它发出任何东西时,智能手机仍然直接接收它发出的内容。

3 个答案:

答案 0 :(得分:0)

我搜寻了蓝牙类资源。乍一看,该解决方法似乎是合法的。首先尝试:

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设备的套接字。如果在创建套接字时bluedevice设备为null,则createRfcommSocket方法似乎为您自己的设备创建了一个套接字。我不确定这将如何发生,但是如果异常后raspberryPi的状态有所改变,我想可能是值得研究的。

在raspi方面:如果您只是同时启动这两个线程,那并不意味着您一直在向“ / dev / rfcomm0”发送消息并进行刷新。我建议您对其进行更改,以使raspi通过发送回所需的消息而不是一直发送垃圾邮件来响应收到的消息。我不确定这是否是您的问题的一部分,但这至少会使调试和开发更加容易。

答案 1 :(得分:-1)

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

答案 2 :(得分:-1)

我认为您在写作方面遇到困难
据我所知,对于缓冲区,应使用\ n和...

import React, {useState} from 'react';
import { BrowserRouter as Router, Switch, Route, Link, Redirect } from "react-router-dom";

import Computers from "../components/Computers";
import Mobiles from "../components/Mobiles";
import Tablets from "../components/Tablets";

const PostAd = (props) => {

    const [selectedOption, setSelectedOption]=useState("");

    const onChangeSelectedOption = (e) => {
        const selectedOption = e.value;
        setSelectedOption(e);
    };

    return(
        <div className="container">
            <h4 className="" style={{alignText:"center"}}>Post Your Advertisement</h4>
            
            <div>
              <Row>
                <Col xs={3}></Col>
                <Col xs={5}>              
                  <AsyncSelect 
                  placeholder="Search for Categories.."
                  loadOptions={loadOptions}
                  onChange={onChangeSelectedOption}
                  />              
                </Col>  
              </Row><hr/>
              </div>

              <Router>
              <div>
              <Row>
                <Col xs={4}>
                    <ul>
                        <li>Electronics
                           <ul>
                               <li><Link to="/computer">computer</Link></li>
                               <li><Link to="/mobiles">Mobiles</Link></li>
                               <li><Link to="/tablets">Tablets</Link></li>
                           </ul>
                        </li>
                    </ul>
                </Col>      
              </Row>
              <div>
                <Switch>
                    <Route exact path="/computers" component={Computers} />
                    <Route exact path="/mobiles" component={Mobiles} />
                    <Route exact path="/tablets" component={Tablets} />
                </Switch>
              </div>
            </div>
            </Router>           
        </div>
    )
};
export default PostAd;

但是我更喜欢结合使用bluetoothWriter.write("This is RaspPi\n"); DataOutputStream

阅读:

BufferedReader

写:

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

最好纠正亲爱的朋友对flush()的观点...

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