藍牙通信

藍牙通信的大概步驟如下:

1,首先開啟藍牙

2,搜索可用設(shè)備

3,創(chuàng)建藍牙socket,獲取輸入輸出流

4,讀取和寫入數(shù)據(jù)

5,斷開連接關(guān)閉藍牙

首先要知道幾個類,BluetoothAdapter,BluetoothGatt,BluetoothDevice,BluetoothCattService,BluetoothCattCharacteristic。

第一個是藍牙設(shè)配器,對藍牙的操作都需要用到它,很重要,BluetoothGatt作為中央來使用和處理數(shù)據(jù),使用時有一個回調(diào)方法BluetoothGattCallback返回中央的狀態(tài)和周邊提供的數(shù)據(jù),BluetoothCattService作為周邊來提供數(shù)據(jù);BluetoothGattServerCallback返回周邊的狀態(tài)。BluetoothDevice是藍牙設(shè)備,BluetoothCattCharacteristic是藍牙設(shè)備的特征。

看著有點亂,我們來打個比喻:BluetoothDevice為學校,BluetoothGatt為學校到達某一個班級的通道,BluetoothCattService為學校的某一個班級,BluetoothCattCharacteristic為班級中的某一個學生。那么藍牙連接通信的過程就是這樣,BluetoothAdapter先找到學校(就是連接目的設(shè)備),再通過通道找到目標班級,最后從班級中找到目標學生,這個學生就是我們設(shè)備之間通信的中介,很重要,學校有唯一的MAC地址,班級有唯一的serviceUUID,學生有唯一的charactersticUUID(相當于學號),所以就是在一所學校找一個學生的問題,好了,應(yīng)該了解了吧。

藍牙通信原理介紹:?

藍牙通信和socket通信原理基本上是一致的,下面我給大家上一張圖(圖為Socket通信圖)。

藍牙客戶端Socket的與Sokcet流程是一樣的,只不過參數(shù)不同而已。如下:?

1、創(chuàng)建客戶端藍牙Sokcet?

2、創(chuàng)建連接?

3、讀寫數(shù)據(jù)?

4、關(guān)閉

服務(wù)端socket:?

1、創(chuàng)建服務(wù)端藍牙Socket?

2、綁定端口號(藍牙忽略)?

3、創(chuàng)建監(jiān)聽listen(藍牙忽略, 藍牙沒有此監(jiān)聽,而是通過whlie(true)死循環(huán)來一直監(jiān)聽的)?

4、通過accept(),如果有客戶端連接,會創(chuàng)建一個新的Socket,體現(xiàn)出并發(fā)性,可以同時與多個socket通訊)?

5、讀寫數(shù)據(jù)?

6、關(guān)閉

下面看客戶端代碼:

/**?

*Title: ConnectThread

*Description: 客戶端邏輯: 客戶端的線程,處理客戶端socket

*Company: ihaveu

@authorMaWei * @date2017/12/26?*/

public classConnectThreadextendsThread{?

?private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);

? ? /** 客戶端socket*/? ??

private final BluetoothSocket mmSoket;

? ? /** 要連接的設(shè)備*/? ??

private final BluetoothDevice mmDevice;

? ? private BluetoothAdapter mBluetoothAdapter;

? ? /** 主線程通信的Handler*/? ?

?private final Handler mHandler;

? ? /** 發(fā)送和接收數(shù)據(jù)的處理類*/? ?

?private ConnectedThread mConnectedThread;

? ? public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {

? ? ? ? mmDevice = device;

? ? ? ? mBluetoothAdapter = bluetoothAdapter;

? ? ? ? mHandler = mUIhandler;

? ? ? ? BluetoothSocket tmp = null;

? ? ? ? try {

? ? ? ? ? ? // 創(chuàng)建客戶端Socket

? ? ? ? ? ? tmp = device.createRfcommSocketToServiceRecord(MY_UUID);

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? mmSoket = tmp;

? ? }

? ? @Override? ? public void run() {

? ? ? ? super.run();

? ? ? ? // 關(guān)閉正在發(fā)現(xiàn)設(shè)備.(如果此時又在查找設(shè)備,又在發(fā)送數(shù)據(jù),會有沖突,影響傳輸效率)

? ? ? ? mBluetoothAdapter.cancelDiscovery();

? ? ? ? try {

? ? ? ? ? ? // 連接服務(wù)器

? ? ? ? ? ? mmSoket.connect();

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? // 連接異常就關(guān)閉

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? mmSoket.close();

? ? ? ? ? ? } catch (IOException e1) {

? ? ? ? ? ? }

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? manageConnectedSocket(mmSoket);

? ? }

? ? private void manageConnectedSocket(BluetoothSocket mmSoket) {

? ? ? ? // 通知主線程連接上了服務(wù)端socket,更新UI

? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER);

? ? ? ? // 新建一個線程進行通訊,不然會發(fā)現(xiàn)線程堵塞

? ? ? ? mConnectedThread = new ConnectedThread(mmSoket,mHandler);

? ? ? ? mConnectedThread.start();

? ? }

? ? /**

? ? * 關(guān)閉當前客戶端

? ? */? ? public void cancle() {

? ? ? ? try {

? ? ? ? ? ? mmSoket.close();

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

? ? /**? ? * 發(fā)送數(shù)據(jù)? ? * @paramdata? ? */

? ? public void sendData(byte[] data) {

? ? ? ? if(mConnectedThread != null) {

? ? ? ? ? ? mConnectedThread.write(data);

? ? ? ? }

? ? }

}

服務(wù)端代碼:

/** *

Title: AccepThread

*

Description: 服務(wù)端Socket通過accept()一直監(jiān)聽客戶端連接的線程

*

Company: ihaveu

* * @authorMaWei * @date2017/12/26 */

public classAccepThreadextendsThread{

?/** 連接的名稱*/?

?private static final String NAME = "BluetoothClass";

? ? /** UUID*/? ??

private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);

? ? /** 服務(wù)端藍牙Sokcet*/? ??

private final BluetoothServerSocket mmServerSocket;

? ? private final BluetoothAdapter mBluetoothAdapter;

? ? /** 線程中通信的更新UI的Handler*/? ??

private final Handler mHandler;

? ? /** 監(jiān)聽到有客戶端連接,新建一個線程單獨處理,不然在此線程中會堵塞*/? ?

?private ConnectedThread mConnectedThread;

? ? public AccepThread(BluetoothAdapter adapter, Handler handler) throws IOException {

? ? ? ? mBluetoothAdapter = adapter;

? ? ? ? this.mHandler = handler;

? ? ? ? // 獲取服務(wù)端藍牙socket? ? ? ?

?mmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);

? ? }

? ? @Override? ? public void run() {

? ? ? ? super.run();

? ? ? ? // 連接的客戶端soacket

? ? ? ? BluetoothSocket socket = null;

? ? ? ? // 服務(wù)端是不退出的,要一直監(jiān)聽連接進來的客戶端,所以是死循環(huán)

? ? ? ? while (true){

? ? ? ? ? ? // 通知主線程更新UI,客戶端開始監(jiān)聽

? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING);

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? // 獲取連接的客戶端socket

? ? ? ? ? ? ? ? socket =? mmServerSocket.accept();

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? // 通知主線程更新UI, 獲取異常

? ? ? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_ERROR);

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? // 服務(wù)端退出一直監(jiān)聽線程

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? ? ? if(socket != null) {

? ? ? ? ? ? ? ? // 管理連接的客戶端socket

? ? ? ? ? ? ? ? manageConnectSocket(socket);

? ? ? ? ? ? ? ? // 這里應(yīng)該是手動斷開,案例應(yīng)該是只保證連接一個客戶端,所以連接完以后,關(guān)閉了服務(wù)端socket

? ? ? ? ? ? ? ? try {

//? ? ? ? ? ? ? ? ? ? mmServerSocket.close();

//? ? ? ? ? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);

//? ? ? ? ? ? ? ? } catch (IOException e) {

//? ? ? ? ? ? ? ? ? ? e.printStackTrace();//? ? ? ? ? ? ? ? }? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? /**? ? * 管理連接的客戶端socket? ??

?* @paramsocket? ? */? ??

private void manageConnectSocket(BluetoothSocket socket) {

? ? ? ? // 只支持同時處理一個連接

? ? ? ? // mConnectedThread不為空,踢掉之前的客戶端

? ? ? ? if(mConnectedThread != null) {

? ? ? ? ? ? mConnectedThread.cancle();

? ? ? ? }

? ? ? ? // 主線程更新UI,連接到了一個客戶端

? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_GOT_A_CLINET);

? ? ? ? // 新建一個線程,處理客戶端發(fā)來的數(shù)據(jù)

? ? ? ? mConnectedThread = new ConnectedThread(socket, mHandler);

? ? ? ? mConnectedThread.start();

? ? }

? ? /**

? ? * 斷開服務(wù)端,結(jié)束監(jiān)聽

? ? */? ? public void cancle() {

? ? ? ? try {

? ? ? ? ? ? mmServerSocket.close();

? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

? ? /**? ? * 發(fā)送數(shù)據(jù)

? ? * @paramdata? ? */? ??

?public void sendData(byte[] data){

? ? ? ? if(mConnectedThread != null) {

? ? ? ? ? ? mConnectedThread.write(data);

? ? ? ? }

? ? }

}

下面看一個共同通訊處理類:

/** *

Title: ConnectedThread

*Description: 客戶端和服務(wù)端 處理 發(fā)送數(shù)據(jù) 和獲取數(shù)據(jù)

*/

publicclassConnectedThreadextendsThread{

/** 當前連接的客戶端BluetoothSocket*/

privatefinalBluetoothSocket mmSokcet;

/** 讀取數(shù)據(jù)流*/

privatefinalInputStream mmInputStream;

/** 發(fā)送數(shù)據(jù)流*/

privatefinalOutputStream mmOutputStream;

/** 與主線程通信Handler*/

privateHandler mHandler;

privateString TAG ="ConnectedThread";

publicConnectedThread(BluetoothSocket socket,Handler handler) {

?mmSokcet = socket; mHandler = handler;

?InputStream tmpIn =null;

?OutputStream tmpOut =null;

try{?

?????????tmpIn = socket.getInputStream();

?????????tmpOut = socket.getOutputStream();?

?}catch(IOException e) {

?e.printStackTrace();

?}

?mmInputStream = tmpIn;?

?mmOutputStream = tmpOut;

?}

@Overridepublicvoidrun() {

super.run();

????????byte[] buffer =newbyte[1024];

????????while(true) {

????????try{

// 讀取數(shù)據(jù)

????????????????intbytes = mmInputStream.read(buffer);

? ? ? ? ? ?if(bytes >0) {

?????????String data =newString(buffer,0,bytes,"utf-8");

????????// 把數(shù)據(jù)發(fā)送到主線程, 此處還可以用廣播

????????Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA,data);?

?????????mHandler.sendMessage(message);?

}

?????????Log.d(TAG,"messge size :"+ bytes);

????????????????}catch(IOException e)

?????????????????{ e.printStackTrace();

?????????????}?

?????????}?

?}

// 踢掉當前客戶端

publicvoidcancle() {

????????????????try{?

????????????????????mmSokcet.close();

? ? ????????? }catch(IOException e) {?

?????????????e.printStackTrace();?

?????????}?

?}

/** * 服務(wù)端發(fā)送數(shù)據(jù) *?

@paramdata */

publicvoidwrite(byte[] data) {

????????????????????try{?

?????????????????????????????????mmOutputStream.write(data);

?????????????????????}catch(IOException e) {?

?????????????????????e.printStackTrace();?

?????????????????}?

? ? ? ? ? ?}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容