我目前正在尝试使用蓝牙在两个 Android 设备之间发送一些数据。我读过很多有关蓝牙传输、套接字和流的问题。到目前为止还没有任何运气。 连接部分工作正常。我获取设备地址,然后使用以下命令打开连接:
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(myOtherDeviceAdress);
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(myUUID));
socket.connect();
然后尝试使用OutputStream
发送一些数据
OutputStream mmout=tmp.getOutputStream();
byte[] toSend="Hello World!".getBytes();
mmout.write(toSend);
mmout.flush();
在接收端:
mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("ccv_prototype", UUID.fromString(myUUID));
mBluetoothSocket = mBluetoothServerSocket.accept(3 * 1000);
InputStream is = mBluetoothSocket.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(is));
然后,不同的版本尝试读取缓冲区,目前:
int c;
StringBuilder response = new StringBuilder();
try {
while ((c = r.read()) != -1) {
//Since c is an integer, cast it to a char. If it isn't -1, it will be in the correct range of char.
response.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
String result = response.toString();
Log.d("MyTag", "Received String: " + result);
我的问题是,如果我不关闭OutputStream
,接收端永远不会收到EOF,但是如果我添加mmout.close();
,它甚至没有时间阅读我想发送的消息就关闭了。到目前为止,我唯一的想法是将特定 token 作为 EOF 发送,但这听起来不对。
我错过了什么? 任何帮助表示赞赏。
最佳答案
简单的答案是肯定的。您应该发送一个特定的 token 来表示 EOF。当您在蓝牙套接字上执行 read()
操作时,如果有数据可供读取,它将立即返回一些数据,否则调用 read()
将阻塞直到有一些数据,或发生一些IO异常(例如连接断开)。这就是为什么您必须使用Thread
,特别是对于蓝牙套接字读写操作。您尝试做的是依靠 BufferedReader
返回 -1 来指示“没有更多数据”。遗憾的是,事情并非如此。 -1 仅在出现某些 IO 异常或连接关闭时才会发生。
检测您的信息(即您的数据包)的开始和结束位置,或者确实确定整个通信 session 何时结束,是您在自己的应用程序协议(protocol)(或者当然是现有协议(protocol))中自行处理的事情)通过套接字工作。对于任何通过流式套接字工作的协议(protocol)来说,这是一个重要的概念。一个很好的例子是 HTTP,正如您所知,HTTP 通常是通过 TCP 使用的。快速浏览一下 HTTP 将向您展示 (a) HTTP 协议(protocol)如何使用 header 来告诉接收者整个 HTTP“消息”还需要多少字节,以及 (b) HTTP header 还如何用于协商何时连接应该关闭。您不能做的是尝试使用套接字本身的方法来确定发送者何时完成消息写入。同样,如果一端要知道另一端想要关闭连接,则应通过应用程序协议(protocol)进行协商。
关于Android蓝牙socket数据传输和生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27928364/