蓝牙通信

蓝牙通信的大概步骤如下:

1,首先开启蓝牙

2,搜索可用设备

3,创建蓝牙socket,获取输入输出流

4,读取和写入数据

5,断开连接关闭蓝牙

首先要知道几个类,BluetoothAdapter,BluetoothGatt,BluetoothDevice,BluetoothCattService,BluetoothCattCharacteristic。

第一个是蓝牙设配器,对蓝牙的操作都需要用到它,很重要,BluetoothGatt作为中央来使用和处理数据,使用时有一个回调方法BluetoothGattCallback返回中央的状态和周边提供的数据,BluetoothCattService作为周边来提供数据;BluetoothGattServerCallback返回周边的状态。BluetoothDevice是蓝牙设备,BluetoothCattCharacteristic是蓝牙设备的特征。

看着有点乱,我们来打个比喻:BluetoothDevice为学校,BluetoothGatt为学校到达某一个班级的通道,BluetoothCattService为学校的某一个班级,BluetoothCattCharacteristic为班级中的某一个学生。那么蓝牙连接通信的过程就是这样,BluetoothAdapter先找到学校(就是连接目的设备),再通过通道找到目标班级,最后从班级中找到目标学生,这个学生就是我们设备之间通信的中介,很重要,学校有唯一的MAC地址,班级有唯一的serviceUUID,学生有唯一的charactersticUUID(相当于学号),所以就是在一所学校找一个学生的问题,好了,应该了解了吧。

蓝牙通信原理介绍: 

蓝牙通信和socket通信原理基本上是一致的,下面我给大家上一张图(图为Socket通信图)。

蓝牙客户端Socket的与Sokcet流程是一样的,只不过参数不同而已。如下: 

1、创建客户端蓝牙Sokcet 

2、创建连接 

3、读写数据 

4、关闭

服务端socket: 

1、创建服务端蓝牙Socket 

2、绑定端口号(蓝牙忽略) 

3、创建监听listen(蓝牙忽略, 蓝牙没有此监听,而是通过whlie(true)死循环来一直监听的) 

4、通过accept(),如果有客户端连接,会创建一个新的Socket,体现出并发性,可以同时与多个socket通讯) 

5、读写数据 

6、关闭

下面看客户端代码:

/** 

*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;

    /** 要连接的设备*/    

private final BluetoothDevice mmDevice;

    private BluetoothAdapter mBluetoothAdapter;

    /** 主线程通信的Handler*/   

 private final Handler mHandler;

    /** 发送和接收数据的处理类*/   

 private ConnectedThread mConnectedThread;

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

        mmDevice = device;

        mBluetoothAdapter = bluetoothAdapter;

        mHandler = mUIhandler;

        BluetoothSocket tmp = null;

        try {

            // 创建客户端Socket

            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);

        } catch (IOException e) {

            e.printStackTrace();

        }

        mmSoket = tmp;

    }

    @Override    public void run() {

        super.run();

        // 关闭正在发现设备.(如果此时又在查找设备,又在发送数据,会有冲突,影响传输效率)

        mBluetoothAdapter.cancelDiscovery();

        try {

            // 连接服务器

            mmSoket.connect();

        } catch (IOException e) {

            // 连接异常就关闭

            try {

                mmSoket.close();

            } catch (IOException e1) {

            }

            return;

        }

        manageConnectedSocket(mmSoket);

    }

    private void manageConnectedSocket(BluetoothSocket mmSoket) {

        // 通知主线程连接上了服务端socket,更新UI

        mHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER);

        // 新建一个线程进行通讯,不然会发现线程堵塞

        mConnectedThread = new ConnectedThread(mmSoket,mHandler);

        mConnectedThread.start();

    }

    /**

    * 关闭当前客户端

    */    public void cancle() {

        try {

            mmSoket.close();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

    /**    * 发送数据    * @paramdata    */

    public void sendData(byte[] data) {

        if(mConnectedThread != null) {

            mConnectedThread.write(data);

        }

    }

}

服务端代码:

/** *

Title: AccepThread

*

Description: 服务端Socket通过accept()一直监听客户端连接的线程

*

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);

    /** 服务端蓝牙Sokcet*/    

private final BluetoothServerSocket mmServerSocket;

    private final BluetoothAdapter mBluetoothAdapter;

    /** 线程中通信的更新UI的Handler*/    

private final Handler mHandler;

    /** 监听到有客户端连接,新建一个线程单独处理,不然在此线程中会堵塞*/   

 private ConnectedThread mConnectedThread;

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

        mBluetoothAdapter = adapter;

        this.mHandler = handler;

        // 获取服务端蓝牙socket       

 mmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);

    }

    @Override    public void run() {

        super.run();

        // 连接的客户端soacket

        BluetoothSocket socket = null;

        // 服务端是不退出的,要一直监听连接进来的客户端,所以是死循环

        while (true){

            // 通知主线程更新UI,客户端开始监听

            mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING);

            try {

                // 获取连接的客户端socket

                socket =  mmServerSocket.accept();

            } catch (IOException e) {

                // 通知主线程更新UI, 获取异常

                mHandler.sendEmptyMessage(Constant.MSG_ERROR);

                e.printStackTrace();

                // 服务端退出一直监听线程

                break;

            }

            if(socket != null) {

                // 管理连接的客户端socket

                manageConnectSocket(socket);

                // 这里应该是手动断开,案例应该是只保证连接一个客户端,所以连接完以后,关闭了服务端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);

        // 新建一个线程,处理客户端发来的数据

        mConnectedThread = new ConnectedThread(socket, mHandler);

        mConnectedThread.start();

    }

    /**

    * 断开服务端,结束监听

    */    public void cancle() {

        try {

            mmServerSocket.close();

            mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

    /**    * 发送数据

    * @paramdata    */    

 public void sendData(byte[] data){

        if(mConnectedThread != null) {

            mConnectedThread.write(data);

        }

    }

}

下面看一个共同通讯处理类:

/** *

Title: ConnectedThread

*Description: 客户端和服务端 处理 发送数据 和获取数据

*/

publicclassConnectedThreadextendsThread{

/** 当前连接的客户端BluetoothSocket*/

privatefinalBluetoothSocket mmSokcet;

/** 读取数据流*/

privatefinalInputStream mmInputStream;

/** 发送数据流*/

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{

// 读取数据

                intbytes = mmInputStream.read(buffer);

           if(bytes >0) {

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

        // 把数据发送到主线程, 此处还可以用广播

        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(); 

         } 

 }

/** * 服务端发送数据 * 

@paramdata */

publicvoidwrite(byte[] data) {

                    try{ 

                                 mmOutputStream.write(data);

                     }catch(IOException e) { 

                     e.printStackTrace(); 

                 } 

           }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355