蓝牙模块?浅谈蓝牙通信流程?

这里介绍的蓝牙通信和蓝牙模块?浅谈蓝牙通信流程?,下面小编就来为你解答

    话不多说我们直接步入正题,下面是一个思维导图:

            首先我们先与另外两种通信方案进行一下对比:


配对流程:

1. 注册适配器打开蓝牙

2.搜索附近设备和已配对设备

3. 选择未配对设备进行配对

4.选择已配对设备进行连接通信


通信工作流程:                                                     

1.服务端先建立一个服务端套接字Socket,然后该套接字开始监听客户端的连接。                        

2 .客户端也建立一个socket,然后向服务端发起连接,这时候如果没有异常就算两个设备连接成功了。  

3.这时候客户端和服务端都会持有一个Socket,利用该Socket可以发送和接收消息。


注册适配器并打开蓝牙

<!-- 蓝牙通讯权限 -->

<uses-permission android:name="android.permission.BLUETOOTH" />//一些配置连接蓝牙的权限

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />//进行操作的权限

<!-- 6.0以上需要的权限 -->

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

在onCreate()方法里,获取蓝牙适配器

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

BluetoothAdapter这个类常用的方法有:

getDefaultAdapter: 获取本地的蓝牙适配器

enable(); 打开蓝牙(不带提示框 但是手机有自带的。。。)

disable(); 关闭蓝牙

isEnabled(): 本地蓝牙是否打开

getAddress(); 获取自己的蓝牙MAC地址

cancelDiscovery() 停止扫描

isDiscovering() 是否正在处于扫描过程中

getState():获取本地蓝牙适配器的状态

getScanMode(): 获取本地蓝牙适配器的当前蓝牙扫描模式。

详细用法表

接下来为了保险起见先判断设备是否支持蓝牙:

if(mBluetoothAdapter == null){

        Toast.makeText(this,"本地蓝牙不可用",Toast.LENGTH_SHORT).show();

        finish(); //退出应用

}

确认支持蓝牙的话就可以调用蓝牙适配器的方法了:

String Address = bluetoothAdapter.getAddress(); //获取本机蓝牙MAC地址

String Name = bluetoothAdapter.getName(); //获取本机蓝牙名称

// 若蓝牙没打开

if(!bluetoothAdapter.isEnabled()){

        bluetoothAdapter.enable(); //打开蓝牙

}

打开蓝牙的两种方式:

第一种打开方法:调用enable

第二种打开方法,调用系统API去打开蓝牙

mBluetoothAdapter.enable();

//不会自动提示用户默认打开 有的手机还是会提示的

Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(intent, REQUEST_OPEN_BT_CODE); //CODE值只是标记可以更改

//会以Dialog样式显示一个Activity , 我们可以在onActivityResult()方法去处理返回值


搜索附近设备和已配对设备

设置可以被搜索到

//设置可以被搜索到

//判断蓝牙适配器的当前蓝牙扫描模式

 if(mBluetoothAdapter.getScanMode()!=BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){

        Intent discoverableIntent=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

        // 设置被发现时间,最大值是3600秒,0表示设备总是可以被发现的(小于0或者大于3600则会被自动设置为120秒)

        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);

        startActivity(discoverableIntent);

}

接下来开始搜索附近:

判断是否正在搜索如果是就停止搜索之类的

if (!mBluetoothAdapter.isDiscovering()) {//判断是否正在搜索

        mBluetoothAdapter.startDiscovery();//开始搜索附近设备

        textView2.setText("正在搜索...");

} else {

    mBluetoothAdapter.cancelDiscovery();//停止搜索

}

搜索附近需要先注册个广播来监听查询附近蓝牙设备:

蓝牙扫描时,扫描到任一远程蓝牙设备时,会发送此广播。两种广播用一个就行

静态注册就是在AndroidManifest.xml文件中定义,

注册的广播接收器必须继承BroadReceiver 动态注册就是在程序中使用Context.registerReceiver注册。

动态广播

//注册广播

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);//搜索到设备

registerReceiver(receiver, filter);

IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束

registerReceiver(receiver, filter2);

静态广播

<!-- 广播接收 -->

<receiver android:name="包名.类名" >

<intent-filter android:priority="1000">

<action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED"/>

<action android:name="android.bluetooth.device.action.FOUND" />

</intent-filter>

</receiver>

new个BroadcastReceiver来接收:

广播一旦发送这边就会调用onReceive()方法

BroadcastReceiver receiver = new BroadcastReceiver() {

        @Override

        public void onReceive(Context context, Intent intent) {

                String action = intent.getAction();

                if (action.equals(BluetoothDevice.ACTION_FOUND)) {

                //获取已配对蓝牙设备

                        Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();

                        for (BluetoothDevice bonddevice : devices) {

                                mPeiDuiList.add(bonddevice);

                                peiDuiAdapter.notifyDataSetChanged();

                        }

                        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                        //判断未配对的设备

                        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {

                                mFuJinList.add(device);

                                fuJinAdapter.notifyDataSetChanged();

                         }

                } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {

                        textView2.setText("搜索完成...");

                }

        }

};

我这边是创建了两个集合分别把已配对的和附近的储存进去

private ArrayList<BluetoothDevice> mPeiDuiList = new ArrayList<>();

private ArrayList<BluetoothDevice> mFuJinList = new ArrayList<>();


选择未配对设备进行配对

这里用到了蓝牙设备BluetoothDevice

BluetoothDevice用于指代某个蓝牙设备,通常表示对方设备

getName:获得该设备的名称; 

getAddress:获得该设备的地址; 

createRfcommSocketToServiceRecord:根据UUID创建并返回一个BluetoothSocket。

1 配对

两个设备建立连接以后,就可以进行一个配对的过程。

配对进行的时候,会产生一个密钥用来加密与鉴别连接。一个典型的情况是,从机设备会要求主机设备提供一个密码来完成一个配对过程。

这个密码可以是固定的例如“000000”,也可以是提供给上层的随机产生的一个值。当主机设备发送一个正确的密码是,这两个设备就会相互交换密钥来加密并鉴别连接。

2 绑定

很多情况下,两个设备会需要经常性的断开连接,连接这样的过程,BLE有一个安全功能,允许两台设备配对的时候给对方一个长期的一套安全密钥。

这种机制称作为绑定。允许两个设备再次连接时不需要再次进行配对就能从新加密与鉴别,只要他们存储了这个安全密钥。

//点击附近的开始配对

mBluetoothAdapter.cancelDiscovery();//停止搜索

String address = mFuJinList.get(position).getAddress();

Toast.makeText(MainActivity.this, mFuJinList.get(position).getName() + "配对中。。。", Toast.LENGTH_SHORT).show();

try {

        //调用工具类与设备配对

        //已知自己的地址 点击获取对方的地址 配对

        remoteDevice = mBluetoothAdapter.getRemoteDevice(address);//通过mac地址获取蓝牙设备

        ClsUtils.createBond(remoteDevice.geTCLass(), remoteDevice);

} catch (Exception e) {

e.printStackTrace();

}

这里用到了一个配对工具类ClsUtils

package com.example.lin.mylanya.utils;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import android.bluetooth.BluetoothDevice;

import android.util.Log;

public class ClsUtils {

/**

* 与设备配对 参考源码:platform/packages/apps/Settings.git

* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java

*/

static public boolean createBond(Class btClass,BluetoothDevice btDevice) throws Exception {

        Method createBondMethod = btClass.getMethod("createBond");

        Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);

        return returnValue.booleanValue();

}

/**

* 与设备解除配对 参考源码:platform/packages/apps/Settings.git

* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java

*/

        static public boolean removeBond(Class btClass,BluetoothDevice btDevice) throws Exception {

                Method removeBondMethod = btClass.getMethod("removeBond");

                Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);

                return returnValue.booleanValue();

        }

}

 

选择已配对设备进行连接通信

通信需要创建客户端和服务器来建立连接

服务器一般是在打开蓝牙后创建这里的ChatController是通信的工具类 这个方法里面调用了服务器线程(AccepThread)的启动方法

if (!mBluetoothAdapter.isEnabled()) {//判断蓝牙是否打开

        mBluetoothAdapter.enable();//打开蓝牙

}

ChatController.getInstance().waitingForFriends(mBluetoothAdapter, handler);//等待客户端来连接

 服务器端建立套接字,等待客户端连接,

调用BluetoothAdapter的listenUsingRfcommWithServiceRecord方法,产生一个BluetoothServerSocket对象,

然后调用BluetoothServerSocket对象的accept方法,

注意accept方法会产生阻塞,直到一个客户端连接建立,所以服务器端的socket的建立需要在一个子线程中去做,

AccepThread 

public class AccepThread extends Thread {

        /** 连接的名称*/

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

                try {

                        // 获取连接的客户端socket

                        socket = mmServerSocket.accept();

                } catch (IOException e) {

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

                        mHandler.sendEmptyMessage(Constant.MSG_ERROR);

                        e.printStackTrace();

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

                            break;

                }

        if(socket != null) {

                        // 管理连接的客户端socket

                        manageConnectSocket(socket);

        }

    }

}

/**

* 管理连接的客户端socket

* @param socket

*/

private void manageConnectSocket(BluetoothSocket socket) {

        // 只支持同时处理一个连接

        // mConnectedThread不为空,踢掉之前的客户端

        if(mConnectedThread != null) {

                    mConnectedThread.cancle();

        }

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

        mConnectedThread = new ConnectedThread(socket, mHandler);

        mConnectedThread.start();

}

/**

* 断开服务端,结束监听

*/

public void cancle() {

        try {

                mmServerSocket.close();

                mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);

        } catch (IOException e) {

                e.printStackTrace();

        }

}

/**

* 发送数据

* @param data

*/

        public void sendData(byte[] data){

                if(mConnectedThread != null) {

                mConnectedThread.write(data);

        }

    }

}

蓝牙客户端套接字BluetoothSocket

BluetoothSocket是客户端的Socket,用于与对方设备进行数据通信。

connect:建立蓝牙的socket连接; 

close:关闭蓝牙的socket连接; 

getInputStream:获取socket连接的输入流对象; 

getOutputStream:获取socket连接的输出流对象; 

getRemoteDevice:获取远程设备信息。

服务器和客户端连接上后都需要新建一个线程进行通信不然会线程阻塞

发送数据需要调用BluetoothSocket的getOutputStream(),接收数据需要调用getInputStream()方法

String uuid = java.util.UUID.randomUUID().toString();

一般在创建Socket时需要UUID作为端口的唯一性,如果两台Android设备互联,则没有什么特殊的,

如果让非Android的蓝牙设备连接Android蓝牙设备,则UUID必须使用某个固定保留的UUID

Android中创建UUID:UUID  uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")

 ConnectedThread

public class ConnectedThread extends Thread{

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

        private final BluetoothSocket mmSokcet;

        /** 读取数据流*/

        private final InputStream mmInputStream;

        /** 发送数据流*/

        private final OutputStream mmOutputStream;

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

        private Handler mHandler;

        private String TAG = "ConnectedThread";

        public ConnectedThread(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;

}

@Override

public void run() {

        super.run();

        byte[] buffer = new byte[1024];

        while (true) {

                try {

                        // 读取数据

                        int bytes = mmInputStream.read(buffer);

                        if(bytes > 0) {

                                        String data = new String(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();

                }

            }

}

// 踢掉当前客户端

public void cancle() {

        try {

                mmSokcet.close();

        } catch (IOException e) {

                e.printStackTrace();

        }

}

/**

* 服务端发送数据

* @param data

*/

public void write(byte[] data) {

        try {

                mmOutputStream.write(data);

        } catch (IOException e) {

                e.printStackTrace();

        }

    }

}

ChatController

public class ChatController {

        /**

        * 客户端的线程

        */

        private ConnectThread mConnectThread;

        /**

        * 服务端的线程

        */

          private AccepThread mAccepThread;

          private ChatProtocol mProtocol = new ChatProtocol();

        /**

        * 网络协议的处理函数

        */

        private class ChatProtocol {

                private static final String CHARSET_NAME = "utf-8";

                /**

                * 封包(发送数据)

                * 把发送的数据变成 数组 2进制流

                */

                public byte[] encodePackge(String data) {

                           if (data == null) {

                                    return new byte[0];

                            } else {

                                    try {

                                            return data.getBytes(CHARSET_NAME);

                                    } catch (UnsupportedEncodingException e) {

                                            e.printStackTrace();

                                            return new byte[0];

                                    }

                  }

}

/**

* 解包(接收处理数据)

* 把网络上数据变成自己想要的数据体

*/

public String decodePackage(byte[] netData) {

            if (netData == null) {

                return "";

            } else {

                        try {

                                 return new String(netData, CHARSET_NAME);

                        } catch (UnsupportedEncodingException e) {

                                e.printStackTrace();

                               return "";

                        }

           }

        }

}

/**

* 与服务器连接进行聊天

*/

public void startChatWith(BluetoothDevice device, BluetoothAdapter adapter, Handler handler) {

        mConnectThread = new ConnectThread(device, adapter, handler);

        mConnectThread.start();

}

/**

* 等待客户端来连接

* handler : 用来跟主线程通信,更新UI用的

*/

public void waitingForFriends(BluetoothAdapter adapter, Handler handler) {

    try {

                mAccepThread = new AccepThread(adapter, handler);

                mAccepThread.start();

        } catch (IOException e) {

                e.printStackTrace();

        }

}

/**

* 发出消息

*/

public void sendMessage(String msg) {

        // 封包

        byte[] data = mProtocol.encodePackge(msg);

        if (mConnectThread != null) {

                mConnectThread.sendData(data);

        } else if (mAccepThread != null) {

                mAccepThread.sendData(data);

        }

}


/**

* 网络数据解码

*/

public String decodeMessage(byte[] data){

        return mProtocol.decodePackage(data);

}

/**

* 停止聊天

*/

public void stopChart(){

        if(mConnectThread != null) {

                mConnectThread.cancle();

        }

        if(mAccepThread != null) {

                mAccepThread.cancle();

        }

}

/**

* 以下是单例写法

*/

        private static class ChatControlHolder{

                private static ChatController mInstance = new ChatController();

        }

        public static ChatController getInstance(){

                return ChatControlHolder.mInstance;

        }

}


发送数据

//客户端向服务器发送数据

String s = mEdit.getText().toString();

//发出消息

ChatController.getInstance().sendMessage(s);


//handler接收数据

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

    super.handleMessage(msg);

        switch (msg.what) {

                    case MSG_GOT_DATA:

                    //接收消息

                    String data = (String) msg.obj;

                    Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();

                    break;

       }

    }

};


最后销毁:

@Override

protected void onDestroy() {

        super.onDestroy();

        unregisterReceiver(receiver);//关闭服务

        mBluetoothAdapter.disable();//关闭蓝牙

        ChatController.getInstance().stopChart();//停止聊天

}

蓝牙模块?浅谈蓝牙通信流程?的相关问答如下:

提问:什么是蓝牙通信

回答:蓝牙通信是一种无线技术的标准,可以实现固定设备、移动设备和楼宇个人域网之间的短距离交换.这是一款蓝牙通讯的终端,应用程序,基本上允许两个设备之间的文字通信,应用蓝牙可以免费享受通讯.

提问:您好,我的手机蓝牙无法与蓝牙耳机建立通信是怎么回事啊

回答:那是因为手机和蓝牙之间的连接方法不正确,参照以下正确的连接方式:1,手机打开蓝牙功能,进去搜索蓝牙耳机状态.2,使蓝牙耳机在开机状态,需要长按蓝牙耳机的接听键.3,直到指示灯:蓝灯红灯交替闪烁再松开.4,这个时候蓝牙耳机和手机会再次进入匹对.等手机上面显示此蓝牙型号设备后,点击确定即可连接使用了.

提问:什么是蓝牙通讯?

回答:蓝牙是更方便网上下载资料的吧~

提问:蓝牙手机怎样通信

回答:两手机蓝牙连接.E398设置=》连接=》蓝牙连接=》免提=》查找其他蓝牙设备连接后在想传送的条目中按菜单键,会有相关选项可能是“移动”或者是在“信息中发送”,忘了是哪个了,就能传送出去了.

提问: 蓝牙无线通讯的原理是?它能无线传输哪些信号?它的有效范围是多少?谁能稍微简述一下?

回答:蓝牙(Bluetooth)是由Ericsson、IBM、Intel、Nokia、和Toshiba等5家公司于1998年联合推出的一项最新的无线网络技术 短标成的Bluetooth无线通信距离(10米),以降低发射功率;用外加功率放大器以增加无线通信距离(100米);要详细的给我发消息 我有好多这方面的资料 目前一般用来传输语音和数据

提问:蓝牙的工作原理是什么?

回答:蓝牙通信的主从关系 蓝牙技术规定每一对设备之间进行蓝牙通讯时,必须一个为主角色,另一为从角色,才能进行通信,通信时,必须由主端进行查找,发起配对,建链成...

蓝牙模块?浅谈蓝牙通信流程?的相关热门搜索词:

蓝牙模块,蓝牙通信协议,蓝牙通信原理,蓝牙通信距离,蓝牙通信范围内是什么意思,树莓派蓝牙通信,cc2530蓝牙通信,为什么手机显示无法与蓝牙通信,蓝牙通信的电磁波是蓝光吗,蓝牙通信,

TAG标签: 蓝牙

文章标题:蓝牙模块?浅谈蓝牙通信流程?

转载注明出处:http://www.puyangxw.cn/zonhezixunn/492766.html

说点什么吧
  • 全部评论(0
    还没有评论,快来抢沙发吧!

随机标签推荐

模特自拍自拍杆70国庆阅兵国外方队辽宁省副书记国务院副总理名单预防感冒潞西最美的景点潞西附近的旅游景点潞西交友潞西最好的高中潞西美食潞西最有钱的人潞西最大的商场潞西注册潞西生活傣族潞西70周年阅兵参加的明星全国政协中央经济工作会议解读黑猫阅兵10086mom基金中国成立70周年怎么发李光耀余澎杉德宏人事德宏资讯 濮阳新闻