进行蓝牙连接的两种方式

为了在两台设备间创建一个连接,必须实现服务器端和客户端的机制,因为一个设备必须打开一个Server Socket,而另一个必须发起连接(使用服务器端设备的MAC地址发起连接)。当服务器端和客户端在同一个RFCOMM信道上都有一个BluetoothSocket时,则两端就建立了连接。此刻,每个设备都能获得一个输入输出流,进行数据传输。
服务器端和客户端获得BluetoothSocket的方法是不同的,服务器端是在客户端的连接被接受时才产生一个BluetoothSocket,客户端是在打开一个到服务器端的RFCOMM信道时获得BluetoothSocket的。
蓝牙连接的一种实现技术是,每一个设备都自动准备作为一个服务器,所以每个设备都有一个Server Socket并监听连接。然后每个设备都能作为客户端建立一个到另一个设备的连接。
另外一种替代方法是,一个设备按需打开一个Server Socket,另外一个设备仅作为客户端建立与这个设备的连接。

1.作为服务器连接
如果要连接两个设备,其中一个必须充当服务器,它拥有BluetoothServerSocket。服务器Socket的作用是侦听进来的连接,且在一个连接被接受时返回一个BluetoothSocket对象。从BluetoothServerSocket获取到BluetoothSocket对象之后,BluetoothServerSocket就可以(也应该)丢弃了,除非还要用它接收更多的连接。
下面是建立服务器Socket和接受一个连接的基本步骤:
步骤1 通过调用listenUsingRfcommWithServiceRecord(String, UUID)方法得到一个BluetoothServerSocket对象。字符串参数为服务的标识名称,名字是任意的,可以简单地是应用程序的名称。当客户端试图连接本设备时,它将携带一个UUID用来唯一标识它要连接的服务,UUID必须匹配,连接才会被接受。
步骤2 通过调用accept()来侦听连接请求。这是一个阻塞线程,直到接受一个连接或者产生异常才会返回。当客户端携带的UUID与侦听它Socket注册的UUID匹配,连接请求才会被接受。如果成功,accept()将返回一个BluetoothSocket对象。
步骤3 除非需要再接受另外的连接,否则的话调用close()。close()释放Server Socket及其资源,但不会关闭accept()返回的BluetoothSocket对象。与TCP/IP不同,RFCOMM同一时刻一个信道只允许一个客户端连接,因此大多是情况下意味着在BluetoothServerSocket接受一个连接请求后应该立即调用close()。
accept()调用不应该在主Activity UI线程中进行,因为它是个阻塞线程,会妨碍应用中其他的交互。通常在一个新线程中做BluetoothServerSocket或BluetoothSocket的所有工作来避免线程阻塞。如果需要放弃阻塞线程,可以调用close()方法。
下面是一个服务器组件接受连接的线程示例。

//定义接受线程
private class AcceptThread extends Thread {
	//创建BluetoothServerSocket类
	private final BluetoothServerSocket mmServerSocket;
	public AcceptThread() {
		BluetoothServerSocket tmp = null;
		try {
			//MY_UUID是应用的UUID标识
			tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
		} catch(IOException e) {}
		mmServerSocket = tmp;
	}
	//线程启动时候运行
	public void run() {
		BluetoothSocket socket = null;
		//保持侦听
		while(true) {
			try {
				//接受
				socket = mmServerSocket.accept();
			} catch(IOException e) {
				break;
			}
			//连接被接受
			if(socket!=null) {
				//管理连接
				manageConnectedSocket(socket);
				//关闭连接
				mmServerSocket.close();
				break;
			}
		}
	}
	//关闭连接
	public void cancel() {
		try
		{
			//关闭BluetoothServerSocket
			mmServerSocket.close();
		}
		catch(IOException e) {}
	}
}

本例中,只接受一个进来的连接,一旦连接被接受并获取BluetoothSocket,应用就发送获取到的BluetoothSocket给一个单独的线程,然后关闭BluetoothServerSocket并跳出循环。
---------------------
注意 accept()返回BluetoothSocket后,Socket就建立了连接,所以在客户端就不应该再调用connect()。
---------------------

2.作为客户端连接

为了实现与远程服务器设备的连接,必须首先获得一个代表远程设备BluetoothDevice的对象。然后使用BluetoothDevice对象来获取一个BluetoothSocket以实现连接。
基本步骤如下:
步骤1 使用BluetoothDevice调用方法createRfcommSocketToServiceRecord(UUID)获取一个BluetoothSocket对象。
步骤2 调用connect()建立连接。当调用这个方法的时候,系统会在远程设备上完成一个SDP查找来匹配UUID。如果查找成功并且远程设备接受连接,就共享RFCOMM信道,connect()会返回。这个方法也是一个阻塞的调用。如果连接失败或者超时(12秒)都会抛出异常。
---------------------
注意 要确保在调用connect()时没有同时做设备搜索,如果在搜索设备,该连接尝试会显著变慢,容易导致连接失败。
---------------------
下面是一个发起Bluetooth连接的线程示例。

//定义Bluetooth连接线程
private class ConnectThread extends Thread {
	//新建BluetoothSocket类
	private final BluetoothSocket mmSocket;
	//新建BluetoothDevice对象
	private final BluetoothDevice mmDevice;
	public ConnectThread(BluetoothDevice device) {
		BluetoothSocket tmp = null;
		//赋值给设备
		mmDevice = device;
		try {
			//根据UUID创建并返回一个BluetoothSocket
			tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
		} catch(IOException e) {}
		//赋值给BluetoothSocket
		mmSocket = tmp;
	}
	public void run() {
		//取消发现设备
		mBluetoothAdapter.cancelDiscovery();
		try {
			//连接到设备
			mmSocket.connect();
		} catch(IOException connectException) {
			//无法连接,关闭Socket
			try
			{
				mmSocket.close();
			}
			catch (IOException connectException) {}
			return;
		}
		//管理连接
		manageConnectedSocket(mmSocket);
	}
	//取消连接
	public void cancel() {
		try
		{
			//关闭BluetoothSocket
			mmSocket.close();
		}
		catch(IOException e) {}
	}
}

注意:cancelDiscovery()应用连接操作前被调用。在连接之前,不管搜索有没有进行。该调用都是安全的,不需要确认(当然如果要确认,可以调用isDiscovering()方法)。处理完后别忘了调用close()方法来关闭连接的Socket和释放所有的内部资源。

3.管理连接

如果两个设备成功建立了连接,各自会有一个BluetoothSocket,此时可以在设备间共享数据了。使用BluetoothSocket,传输任何数据通常来说都比较容易,通常如下进行:
+分别使用getInputStream()和getOutputStream()获取输入输出流来处理传输。
+调用read(byte[])和write(byte[])来实现数据读写。
当然,要注意一些实现细节。比如,需要用一个专门的线程来实现流的读写,因为方法read(byte[])和write(byte[])都是阻塞调用。read(byte[])会阻塞,直到流中有数据可读。write(byte[])虽然通常不会阻塞,但是如果远程设备调用read(byte[])不够快而导致中间缓冲区满,它也可能阻塞。所以线程中的主循环应该用于读取InputStream。线程中也应该有单独的方法用来完成写OutputStream。
请看下面的示例:

//连接管理线程
private class ConnectThread extends Thread {
	//新建BluetoothSocket类
	private final BluetoothSocket mmSocket;
	//新建输入流对象
	private final InputStream mmInStream;
	//新建输出流对象
	private final OutputStream mmOutStream;
	public ConnectThread(BluetoothSocket socket) {
		//为BluetoothSocket赋初始值
		mmSocket = socket;
		//输入流赋值为null
		InputStream tmpIn = null;
		//输出流赋值为null
		OutputStream tmpOut = null;
		try {
			//从BluetoothSocket中获取输入流
			tmpIn = socket.getInputStream();
			//从BluetoothSocket中获取输出流
			tmpOut = socket.getOutputStream();
		} catch(IOException e) {}
		//为输入流赋值
		mmInStream = temIn;
		//为输出流赋值
		mmOutStream = temOut;
	}
	public void run() {
		//流的缓冲大小
		byte[] buffer = new byte[1024];
		//用于保存read()所读取的字节数
		int bytes;
		while(true) {
			try
			{
				//从输入流中读取数据
				bytes = mmInStream.read(buffer);
				//发送数据到界面
				mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
			}
			catch ()
			{
				break;
			}
		}
	}
	//发送数据到远程设备
	public void write(byte[] bytes) {
		try
		{
			//写数据到输出流中
			mmOutStream.write(bytes);
		}
		catch(IOException e) {}
	}
	//取消
	public void cancel() {
		try
		{
			//关闭B连接
			mmSocket.close();
		}
		catch(IOException e) {}
	}
}

构造函数中得到需要的流,一旦执行,线程会等待从InputStream来的数据,当read(byte[])返回从流中读到的字节后,数据通过父类的成员Handler被送到主Activity,然后继续等待读取流中的数据。向外发送数据只需简单地调用线程的write()方法。线程的cancel()方法是很重要的,以便连接可以在任何时候通过关闭BluetoothSocket来终止。它总在处理完Bluetooth连接后被调用。

时间: 2024-10-26 06:32:20

进行蓝牙连接的两种方式的相关文章

web.config中配置数据库(多数据)连接的两种方式

这是我的第一篇文章,既然是第一篇了,那就从最基础的只是说起--web.config中配置数据库连接. 网上有很多这方面的资料,但发现并没有一篇从头到位很清楚明了说完的,今天就把我的整理写在这里吧. 在网站开发中,数据库操作是经常要用到的操作,ASP.NET中一般做法是在web.config中配置数据库连接代码,然后在程序中调用数据库连接代码,这样做的好处就是当数据库连接代码需要改变的时候,我们只要修改web.config中的数据库连接代码即可,而不必在修改每一个页面中的数据库连接代码. 在ASP

JAVA连接Oracle两种方式

以前学习.NET连接数据库时,也是做各种的连接配置.而如今在用到java操纵Oracle时,同样是一些的操作.在此总结一下. 1.JDBC_ODBC连接数据库 此方法需要配置ODBC数据源,本机必须有Oracle数据库 1.配置数据源 打开控制面板--管理工具--数据源 2.接下来在代码中连接即可 //使用jdbc_odbc桥接方式连接,需要配置数据源 public static void main(String [] args){ try{ //1.加载驱动 Class.forName("su

网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管理 JDBC事务 DBUtils事务 ThreadLocal 事务特性 并发访问 隔离级别

1.1.1 API详解:注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 原因有2个: >导致驱动被注册2次. >强烈依赖数据库的驱动jar 解决办法: Class.forName("com.mysql.jdbc.Driver"); 1.1.2 API详解:java.sql.Statement接口: 操作sql语句,并返回相应结果 String sql = "某SQL语句&qu

ADB连接手机的两种方式(usb数据线连接和wifi连接)

ADB(Android Debug Bridge)安卓测试桥,它是连接电脑开发端和安卓设备的桥梁,这个安卓设备可以是真实的安卓手机或者平板,也可以是虚拟的安卓模拟器, 这里介绍ADB连接手机的两种方式, 先说USB数据线连接方式, 分三步, 第一步:把安卓设备用Usb数据线连接到电脑上(注意手机上要在设置里"开发模式"打开"USB调试功能") 第二步:要安装ADB驱动程序,有了这个驱动,ADB才能驱动手机,下载地址通用型ADB驱动, 下载后自动安装就行. 第三步:当

Java连接Neo4j的两种方式

1.Neo4j数据库的两种方式 Neo4j可以以两种方式运行: Java应用程序中的嵌入式数据库 通过REST的独立服务器 不管哪一种方式,这个选择不会影响查询和使用数据库的方式. 它是由应用程序的性质(无论是独立服务器还是客户端服务器),性能,监视和数据安全性驱动的架构选择. 1.1Neo4j Server(服务器式数据库) Neo4j Server是互操作性,安全性和监控的最佳选择. 实际上,REST接口允许所有现代平台和编程语言与它进行互操作. 此外,作为独立应用程序,它比嵌入式配置更安全

Centos7.3 下SQL Server 备份及还原的两种方式

Centos7.3 下SQL Server 备份及还原的两种方式 我们前面两篇文章介绍了Centos7.3下SQL Server的安装配置及使用Powershell的管理介绍,今天我们接着介绍如何实现Centos7.3 下SQL Server  备份及还原,有两种方式:1.使用SSMS备份及还原,该方式最为简单也最方便操作的方式,2.使用Linux下SQL Server自带功能命令备份,具体见下: 我们上一篇中创建了一个测试数据库,我们接着拿这个数据库进行测试,我们首先使用第一种方式,使用SSM

不停止MySQL服务增加从库的两种方式

转载自:http://lizhenliang.blog.51cto.com/7876557/1669829 现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库.前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作. 一般在线增加从库有两种方式,一种是通过mysqldump备份主库,恢复到从库,mysqldump是逻辑备份,数据量大时,备份速度会很慢,锁表的时间也会很长.另一种是通过xtrabackup工具

vb.net访问sql server数据库(SqlDataReader和DataSet两种方式)

.net访问数据库的三个基本步骤: 一.连接数据库: 要使用sqlclient命名空间中的sqlconnection类: 定义一个sqlconnection对象: Dim sqlCon As New SqlConnection 要进行的设置有: 1.sqlCon .ConnectionString="server=服务器ip;database=数据库名称;integrated security=ture/false(是否有登录账号密码);uid=用户名 (默认:sa);pwd:登录密码"

不停止 MySQL 服务增加从库的两种方式

不停止 MySQL 服务增加从库的两种方式 提交 我的评论 加载中 已评论 不停止 MySQL 服务增加从库的两种方式 2015-07-12 数据库开发 数据库开发 数据库开发 微信号 DBDevs 功能介绍 分享数据库相关技术文章.教程和工具,另外还包括数据库相关的工作.偶尔也谈谈程序员人生 :) (点击上方蓝字,快速关注我们) 作者:李振良 网址:http://lizhenliang.blog.51cto.com/7876557/1669829 现在生产环境MySQL数据库是一主一从,由于业