3

我正在制作一个 Android 应用程序(EDIT1:在 Nexsus S 的 4.0.3 上开发),它通过蓝牙共享数据 P2P,并且在使两个设备连接时遇到了令人讨厌的障碍。我们的应用程序使用 NFC 将一台设备的 MAC 地址传递给另一台设备。然后,发送者创建一个BlueToothServer 套接字实例并调用accept,而接收者使用它收到的MAC 地址创建一个BluetoothDevice 实例并尝试连接。

我们遇到的问题是从accept() 返回的BluetoothSocket。它的文档清楚地指出它应该返回一个连接的套接字,但它返回一个断开连接的套接字,甚至不能通过调用 connect() 来连接。我已经检查了套接字具有的 MAC 地址并将其清除,并且仅返回的事实 accept() 意味着已成功连接足够长的时间以制作套接字,所以我在这里不知所措,还有什么可以尝试的。

还值得一提的是,接收方的 BluetoothSocket 在此期间声称它实际上已连接。显然,它只是在等待从未来自其他设备的数据时挂起,但是在多个地方使用检查点,我们知道直到那时它总是声称已连接。

对此的任何帮助或建议将不胜感激。

其他相关信息:

发送者和接收者是同一个应用程序,但代表不同的活动。这个应用是一个游戏,加入游戏需要有游戏的人把它给别人,这是由NFC发起的(最终假设通过蓝牙发送的数据是加入所需的游戏数据)。发送者拥有游戏并处于赠送游戏的活动中,而接收者处于想要接收游戏的活动中,然后进入赠送活动以允许他们将游戏传递给其他人。现在说清楚,虽然我们现在可以合并这两个活动,但我们稍后将使用相同的技术作为实际游戏的一部分,无法确保两者都开启同样的活动,

我们还确定 UUID 正确匹配。我们有一个具有恒定 UUID 的全局类,我们只是在某个时候生成并使用它。根据您的目的,UUID 在某些情况下需要是特定的东西,但我也理解它,对于这种特殊用途,我们应该生成自己的。

BluetoothServerSocket 被创建并作为 NdefPushbackComplete 回调的一部分从中调用 accept(),因此在发送方开始设置其服务器套接字之前,另一部电话肯定有​​ Ndef 消息。

客户端或服务器蓝牙代码都没有像网上常见的那样在自己的线程上运行,这是设计使然,因为我们希望交换在任何一方可以做任何其他事情之前完全发生。

如果我忽略了任何重要的事情,我很乐意提供。最后,这是客户端和服务器端代码。它的这个版本使用了一个不安全的套接字,但是我已经尝试了两种方法,并且用于测试它的电话是配对的。

客户:

String s = new String(msg.getRecords()[0].getPayload());
otherBluetoothMACAddress = s;
Log.d(DEV, "WaitingToGetGame: Other BT Address... "
    + otherBluetoothMACAddress);


Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();

Log.d(DEV, "WaitingToGetGame: Getting remote device");
BluetoothDevice bluetoothDevice = bluetoothAdapter
    .getRemoteDevice(otherBluetoothMACAddress);

ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;


try
{
  Log.d(DEV, "WaitingToGetGame: Getting BluetoothSocket");
  bluetoothSocket = bluetoothDevice
      .createInsecureRfcommSocketToServiceRecord(SDP_UUID);

  Log.d(DEV, "WaitingToGetGame: Connecting...");
  bluetoothSocket.connect();

  Log.d(DEV,
      "WaitingToGetGame: Bluetooth "
          + ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
          + "Connected.");

  Log.d(DEV, "WaitingToGetGame: Getting input stream");
  bluetoothInputStream = bluetoothSocket.getInputStream();

  Log.d(DEV,
      "WaitingToGetGame: Bluetooth "
          + ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
          + "Connected.");
  Log.d(DEV, "WaitingToGetGame: Getting output stream");
  bluetoothOutputStream = bluetoothSocket.getOutputStream();

  Log.d(DEV,
      "WaitingToGetGame: Bluetooth "
          + ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
          + "Connected.");
  objectInputStream = new ObjectInputStream(bluetoothInputStream);
  objectOutputStream = new ObjectOutputStream(bluetoothOutputStream);

  Log.d(DEV, this.getClass().getSimpleName() + ": Receiving game data");
  game = (Game) objectInputStream.readObject();

  Log.d(DEV, this.getClass().getSimpleName() + ": Sending acknowledgment.");
  objectOutputStream.writeObject(new Boolean(true));
  objectInputStream.close();
  objectOutputStream.close();
  bluetoothInputStream.close();
  bluetoothOutputStream.close();
  bluetoothInputStream = null; // GC
  bluetoothOutputStream = null; // GC
  bluetoothSocket.close();
  bluetoothSocket = null;

服务器:

BluetoothServerSocket bluetoothServerSocket = null;
ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;

try
{

  Log.d(DEV, this.getClass().getSimpleName()
      + ": Getting BluetoothServerSocket");
  // bluetoothServerSocket = bluetoothAdapter
  // .listenUsingRfcommWithServiceRecord(user.getName(), SDP_UUID);
  bluetoothServerSocket = bluetoothAdapter
      .listenUsingInsecureRfcommWithServiceRecord(user.getName(), SDP_UUID);

  Log.d(DEV, this.getClass().getSimpleName() + ": Waiting for connection.");
  bluetoothSocket = bluetoothServerSocket.accept();
  bluetoothServerSocket.close();
  BluetoothDevice dev = bluetoothSocket.getRemoteDevice();
  Log.d(DEV, dev.getAddress());

  Log.d(DEV, this.getClass().getSimpleName() + ": Bluetooth "
      + ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
      + "Connected.");
  // At this point bluetoothSocket should be ready to use.

  Log.d(DEV, this.getClass().getSimpleName() + ": Getting input stream");
  bluetoothInputStream = bluetoothSocket.getInputStream();

  Log.d(DEV, this.getClass().getSimpleName() + ": Bluetooth "
      + ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
      + "Connected.");


  Log.d(DEV, this.getClass().getSimpleName() + ": Getting output stream");
  bluetoothOutputStream = bluetoothSocket.getOutputStream();

  // Log.d(DEV, this.getClass().getSimpleName()
  // + ": Attempting direct connect()");
  // bluetoothSocket.connect();

  objectInputStream = new ObjectInputStream(bluetoothInputStream);
  objectOutputStream = new ObjectOutputStream(bluetoothOutputStream);


  Log.d(DEV, this.getClass().getSimpleName() + ": Sending game data.");
  objectOutputStream.writeObject(game);

  Log.d(DEV, this.getClass().getSimpleName() + ": Waiting for response.");
  Boolean response = (Boolean) objectInputStream.readObject();

  objectInputStream.close();
  objectOutputStream.close();
  bluetoothInputStream.close();
  bluetoothOutputStream.close();
  bluetoothInputStream = null; // GC
  bluetoothOutputStream = null; // GC
  bluetoothSocket.close();
  bluetoothSocket = null;
}// try
catch( IOException e )
{
  Log.d(
      DEV,
      this.getClass().getSimpleName() + ": "
          + java.util.Arrays.toString(e.getStackTrace()));
  e.printStackTrace();
  return;
}
catch( ClassNotFoundException e )
{
  // TODO Auto-generated catch block
  e.printStackTrace();
}
4

1 回答 1

1

到目前为止,我无法在您的程序中找到错误,但是:

显然,它只是在等待从未来自其他设备的数据时挂起,但是在多个地方使用检查点我们知道,直到那时它总是声称已连接。

实际上,这意味着 2 个设备已连接,只是您的 BT 客户端应用程序没有连接套接字 -> 它连接到其他地方。

你可以尝试几件事:

  • 你必须用 try/catch 包围你的阻塞调用,否则你不能确定你的代码按预期工作。所以环绕bluetoothSocket.connect(); 在您的客户端代码中,并且bluetoothSocket = bluetoothServerSocket.accept(); 在服务器代码中。客户端代码应在 bt 客户端连接错误时捕获 IOException。我认为这是我发现确定客户端连接是否成功的最佳方法!Ofc .isConnected() 之后可以这样做,就像在您的代码中一样。

  • 在 ASyncTask 中运行您的蓝牙代码,如果不是(甚至更好)服务。我知道你宁愿不这样做,但它可能会为你省去很多痛苦。我的 BT 代码从 ASyncTasks 完美运行 - 具有自定义 UUID,在 2 个 Android 之间,在 1 个 Android 和 1 个 BT-USB 加密狗之间,1 个 Android - 1 个嵌入式设备等。

  • 把UUID改成SDP,看看能不能用!

但是有一个问题,您是否尝试过从服务器端传输某些内容?它应该工作..让我知道这是否有效!

于 2012-05-10T06:30:01.023 回答