2012-05-08 45 views
3

我正在製作一個Android應用程序(EDIT1:在Nexusus S上的4.0.3上開發),它通過藍牙共享數據P2P,並且已經遇到了令人討厭的障礙兩個設備連接。我們的應用程序使用NFC將一個設備的MAC地址傳遞給另一個設備。然後發件人創建一個BlueToothServer套接字實例並調用accept,而接收方使用它接收到的MAC地址創建一個BluetoothDevice實例並嘗試連接。BluetoothServerSocket.accept()返回未連接的問題BluetoothSocket

我們遇到的問題是從accept()返回的BluetoothSocket。它的文檔明確指出它應該返回一個連接的套接字,但是它會返回一個斷開連接的套接字,即使通過調用connect()也不能連接。我檢查了套接字所具有的MAC地址並將其清除,僅返回accept()就意味着已成功連接足夠長的時間來創建套接字,所以我不知道該嘗試什麼。

還值得一提的是,接收方的BluetoothSocket在此期間聲稱它實際上已連接。顯然,它只是簡單地等待數據永遠不會來自另一臺設備,而是在多個地方使用檢查點,我們知道直到那個時候它總是聲稱被連接。

任何幫助或建議,將不勝感激。

其他相關信息:

的發送者和接收者是相同的應用程序,但代表了不同的活動。這款應用程序是一款遊戲,其中加入遊戲需要有人將遊戲提供給其他人,這是由NFC發起的(最終假設通過藍牙發送的數據是加入遊戲所需的數據)。發送者擁有遊戲並且處於一個活動中,而接收者正在接收活動,然後進入贈送活動,讓他們將其傳遞給其他人。爲了清楚地說明這一點,儘管我們現在可以合併這兩項活動,但我們稍後將使用相同的技術作爲實際遊戲的一部分,因爲它不可能確保兩者都處於開啓狀態同樣的活動,所以我們需要克服不同的活動問題。

我們也確定UUID匹配正確。我們有一個全局類,它帶有一個我們剛剛在某個點生成並使用的常量UUID。根據你的目的,UUID在某些情況下需要是特定的東西,但是我也理解它,因爲這種特殊用途,我們假設要產生我們自己的。

BluetoothServerSocket創建並接受()作爲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(); 
} 
+0

歡迎來到StackOverflow!寫得很好的問題。您正在測試什麼類型的手機(製造商,型號,Android版本等)? – Jack

+0

好,謝謝!我們正在使用Nexus S上運行的Android 4.0.3。我將編輯它。 –

+0

嘗試連接(在兩個設備上)時,您是否在BondState更改過程中查看過LogCat?它會給出錯誤嗎? – Jack

回答

1

我無法找到你的程序故障,到目前爲止,但:

顯然,它只是簡單地掛起在等待數據從來沒有來自其他設備,但在多個地方使用檢查點,我們知道直到那個時候它總是聲稱被連接。

其實,這意味着2設備連接,只是你的BT客戶端應用程序不會連接套接字 - >它連接到別的地方。

您可以嘗試幾件事情:

  • 則必須用try/catch語句的阻塞調用,否則你不能肯定地說你的代碼工作正常。 So surround bluetoothSocket.connect();在您的客戶端代碼中,以及bluetoothSocket = bluetoothServerSocket.accept();服務器代碼中的客戶端代碼應該在bt客戶端連接錯誤上捕獲IOException。我認爲這是我發現確定客戶端連接是否成功的最佳方式! Ofc .isConnected()可以在之後執行,就像你的代碼一樣。

  • 在ASyncTask中運行你的藍牙代碼,如果沒有(甚至更好)的服務。我知道你寧願不這樣做,但它可以爲你節省很多痛苦。 我的BT代碼運行完全從ASyncTasks - 與自定義UUID,之間2安卓,1安卓和1 BT-USB加密狗,1 Android - 1嵌入式設備等

  • 更改UUID爲SDP,看看是否它的作品呢!

雖然有一個問題,您是否嘗試過從服務器端傳輸某些東西?它應該工作.. 讓我知道這是否有任何工作!

+0

我們所做的一切都在try/catch塊中;這就是我知道它傳遞給我一個未連接的套接字而不是拋出一個IOException,就像它假設的那樣。此外,我無法從服務器端發送任何內容,因爲在未連接時,輸入/輸出流可通過get函數進行檢索,但在嘗試使用它們不連接時會拋出異常。事實上,當服務器嘗試發送數據時,現在就是失敗點。此外,安全和不安全的功能都使用SDP,UUID代表服務記錄,所以你所說的沒有意義。 –

+0

我的不好,我的意思是SPP !!!!當你在它的時候,一次只能嘗試一個代碼。這意味着在某些Android服務器應用程序中使用您的客戶端SPP代碼(00001101-0000-1000-8000-00805F9B34FB),反之亦然! – Radu