BluetoothServerSocket.accept()返回未连接的BluetoothSocket时出现问题

时间:2012-05-08 20:48:28

标签: android sockets bluetooth nfc nfc-p2p

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

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

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

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

其他相关信息:

发件人和收件人是相同的应用程序,但代表不同的活动。这个应用程序是一个游戏,其中加入游戏需要有游戏的人将其提供给其他人,这是由NFC发起的(最终假设通过蓝牙发送的数据是加入所需的游戏数据)。发送者拥有游戏,并且处于一种活动中,并且接收者处于想要接收它的活动中,然后进入赠送活动以允许他们将其传递给其他人。为了明确这一点,虽然我们现在可以合并这两个活动,但我们将在以后使用相同的技术作为实际游戏的一部分,在这个游戏中我们无法确保两者都在相同的活动,所以我们需要在某些时候克服不同的活动问题。

我们也确定UUID正确匹配。我们有一个具有常量UUID的全局类,我们刚刚在某个时刻生成并使用它。根据你的目的,UUID在某些情况下需要特定的东西,但我也理解它,对于这个特殊用途,我们假设生成我们自己的。

创建BluetoothServerSocket并从中调用accept()作为NdefPushbackComplete回调的一部分,因此在发件人开始设置其服务器套接字之前,另一部手机肯定有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();
}

1 个答案:

答案 0 :(得分:1)

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

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

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

您可以尝试以下几种方法:

  • 您必须使用try / catch包围阻止调用,否则您无法确定代码是否按预期工作。 因此,在客户端代码中包含 bluetoothSocket.connect(); ,并在服务器代码中包含 bluetoothSocket = bluetoothServerSocket.accept(); 客户端代码应该在bt客户端连接错误上捕获IOException。我认为这是我发现确定客户端连接是否成功的最佳方式! Ofc .isConnected()可以在之后执行,就像在代码中一样。

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

  • 将UUID更改为SDP,然后查看它是否有效!

但是有一个问题,您是否尝试过从服务器端传输内容?它应该可以工作.. 如果有的话,请告诉我!