Connecting Devices
為了建立兩個裝置上的應用程式之間的連線,你必須執行伺服器端與客戶端的機制,因為一個裝置必須開啟伺服器插口,另一個必須啟動連線(使用伺服器端的MAC位址建立連線),當它們彼此有已連線的BluetoothSocket在相同的RFCOMM頻道上時,表示伺服器端與客戶端彼此已建立連線,在此點,彼此都獲得輸出與輸入的資訊流然後數據傳輸就可以開始了。此部分會在Managing a Connection中學習到。
伺服器端裝置與客戶端裝置都以不同方式獲得所需的BluetoothSocket,伺服器端會在接受連入的時候獲得,客戶端會在開啟通往伺服器端的RFCOMM頻道時獲得。
有一個技術是自動將每個裝置視為伺服器端,因此每個裝置都有一個開啟的伺服器插口並監聽連線,且裝置可以啟動與其他裝置的連線,成為客戶端,另外,一台裝置可以明確地為"主機"連線,並開放伺服器插口點播,其他裝置可以輕易地實現連線。
Connecting as a server
如果你想要連接兩個裝置,一個裝置必須作為伺服器,持有一個開放的BluetoothServerSocket,伺服器插口的目的是監聽連入的請求,並且當它接受後,提供一個已連線的BluetoothSocket。當BluetoothSocket已經從BluetoothServerSocket收購,BluetoothServerSocket應該被丟棄,除非你想接受更多連線。
以下是設置伺服器插口語接受連線的基本程序:
- 呼叫]listenUsingRfcommWithServiceRecord(String , UUID)取得BluetoothServerSocket。
傳入的字串參數是你的服務的可辨識名稱,系統自動地將字串寫入新的Service Dicovery Protocol(SDP)在裝置的資料庫中。參數UUID也是包括在SDP中並且將是客戶端連線許可的基礎,當客戶端視著與此裝置連線,客戶端會帶著唯一辨識想連線伺服器的UUID,這些UUID必須相匹配,連線才會被接受。 - 呼叫accept()方法監聽連線的請求。
這是阻絕式呼叫,當連線已經被接受時或是異常發生時它回傳。連線被接受只在遠端裝置已發送UUID的連線請求,且UUID與已註冊正在監聽的伺服器插口的UUID相匹配時。當連線成功,accept()方法回傳已連線BluetoothSocket。 - 呼叫close()方法,除非你想接受更多連線。
釋放伺服器插口及所有資源,但不會關閉用accept()方法請求來的已連線的BluetoothSocket。不像TCP/IP、RFCOMM一個頻道同時只允許一個客戶端連線,所以在大部分的案例中,在接受一個已連線的插口後,很直覺的立即呼叫BluetoothServerSocket的close()方法。
呼叫accept()方法不應該在主Activity的UI執行續中執行,因為它是一個阻絕式呼叫且將阻止與應用程式的任何互動,由其他新的執行續完成BluetoothServerSocket或是BluetoothSocket的所有工作是比較合理的,退出阻絕式呼叫,比如accept()方法,從其他執行續呼叫在BluetoothServerSocket的close()方法。
舉例:
以下為伺服器組件及接受連線的執行續:
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(socket);
mmServerSocket.close();
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) { }
}
}
此例中,只需一個連入連線,所以只要連線被接受且BluetoothSocket被收購,應用程式就會寄送BluetoothSocket到另一個執行續,關閉BluetoothServerSocket,結束迴圈。
注意當accept()回傳BluetoothSocket,插口已準備好連線,所以無需呼叫connect()方法。
在應用程式中manageConnectedSocket()是一個虛構的方法,啟動執行續來傳輸資料。
通常應該在完成連入的連線工作後關閉BluetoothServerSocket,在此例中,BluetoothSocket被收購,同時close()方法被呼叫,你也許想在你的執行續提供公開方法關閉私有的BluetoothSocket,在你需要關閉監聽伺服器插口事件上。
Connecting as a client
為了與遠端裝置啟動連線(擁有伺服器插口的裝置),你首先必須獲得代表遠端裝置的BluetoothDevice物件,接著你必須用BluetoothDevice物件收購一個BluetoothSocket,並啟動連線。
以下為基本程序:
Connecting as a client
為了與遠端裝置啟動連線(擁有伺服器插口的裝置),你首先必須獲得代表遠端裝置的BluetoothDevice物件,接著你必須用BluetoothDevice物件收購一個BluetoothSocket,並啟動連線。
以下為基本程序:
- 利用BluetoothDevice呼叫createRfcommSocketToServerRecord(UUID)取得BluetoothSocket。
此步驟初始化與BluetoothDevice連線的BluetoothSocket,此處傳入的參數UUID必須與開啟BluetoothServerSocket的裝置的UUID相匹配。利用相同UUID是在應用程式的簡單UUID字串應編碼,並由伺服器端與客戶端所引用。 - 呼叫connect()方法啟動連線。
在呼叫此方法之上,系統執行SDP查找遠端裝置,為了配對UUID。如果查找成功,遠端裝置接受連線,遠端裝置利用連線分享RFCOMM頻道。此方法是阻絕式呼叫,如果任何原因連線失敗、或是connect()時間到了(超過12秒),它就會丟出意外。
因為connect()是阻絕式呼叫,所以此連線應該在與主執行續分開的執行續執行。
舉例:
以下為一個簡單的例子執行一個新的執行續與啟動藍芽連線。
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
注意cancelDiscovery()方法呼叫在連線建立之前,你應該總是在連線之前這樣做,無須檢查它是否運行,呼叫它是安全的。
當你使用BluetoothSocket完後,總要呼叫close()方法清除,立即地關閉連接插口且清除所有資源。
沒有留言:
張貼留言