android - BluetoothServerSocket.accept() 返回未连接的 BluetoothSocket 的问题

标签 android sockets bluetooth nfc nfc-p2p

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

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

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

如有任何帮助或建议,我们将不胜感激。

其他相关信息:

发送者和接收者是同一个应用程序,但代表不同的 Activity 。本应用程序是一款游戏,加入游戏需要有游戏的人将游戏交给其他人,由NFC发起(最终要通过蓝牙发送的数据是加入游戏所需的数据)。发送者拥有游戏并且正在进行赠送游戏的 Activity ,而接收者正在进行想要接收游戏的 Activity ,然后进入赠送 Activity 以允许他们将其传递给其他人。现在要明确这一点,虽然我们现在可以合并这两个 Activity ,但我们稍后将使用相同的技术作为实际游戏的一部分,在这种情况下无法确保两者都开启相同的 Activity ,因此无论如何我们都需要在某个时候克服不同 Activity 的问题。

我们也确信 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();
}

最佳答案

到目前为止我找不到你程序中的错误,但是:

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

实际上,这意味着 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,看看能不能用!

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

关于android - BluetoothServerSocket.accept() 返回未连接的 BluetoothSocket 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10506260/

相关文章:

android - 根访问副作用

java - 打不开项目?

iphone - 一步完成 Facebook SSO 和第三方站点注册?

java - Intent putExtra 方法的最大长度? (强制关闭)

javascript - 与远程服务器上的 Socket.io 建立连接

c - C语言的Socket通信。发送文件内容

java - java socket程序中的ArrayIndexOutOfBounds异常

bluetooth - Arduino上的蓝牙固件?

c# - Xamarin.Forms 的 Plugin.BLE 未检测到设备

Android/iOS 点对点架构