📄 netlayer.java
字号:
import javax.microedition.io.*;
import javax.bluetooth.*;
import java.io.*;
import java.util.*;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.ServiceRecord;
/** 该类的功能是:
* 搜索设备
* 创建一个服务器,然后进行注册
* 搜索远程设备的服务
* 处理远程服务的连接要求
* 建立远程服务的连接
*/
public class NetLayer implements Runnable
{
public final static int SIGNAL_HANDSHAKE = 0;
public final static int SIGNAL_MESSAGE = 1;
public final static int SIGNAL_TERMINATE = 3;
public final static int SIGNAL_HANDSHAKE_ACK = 4;
public final static int SIGNAL_TERMINATE_ACK = 5;
private final static UUID uuid = new UUID("102030405060708090A0B0C0D0E0F010", false);
private final static int SERVICE_TELEPHONY = 0x400000;
//本地蓝牙设备
LocalDevice localDevice = null;
// 本地的发现代理
DiscoveryAgent agent = null;
//本地的服务
StreamConnectionNotifier server;
//回调接口
BTListener callback = null;
//停止标志量
boolean done = false;
//本机用户名
String localName = "";
//活动终结点的列表
Vector endPoints = new Vector();
// 未决的结点,还没发现服务的结点
Vector pendingEndPoints = new Vector();
// map ServiceRecord to EndPoint
Hashtable serviceRecordToEndPoint = new Hashtable();
// synchronization lock
// see DoServiceDiscovery and serviceSearchCompleted
Object lock = new Object();
// timer to schedule task to do service discovery
// see inquiryCompleted
Timer timer = new Timer();
public NetLayer()
{
}
public void init(String name, BTListener callback)
{
try {
this.localName = name;
this.callback = callback;
// initialize the JABWT stack
localDevice = LocalDevice.getLocalDevice();
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
agent = localDevice.getDiscoveryAgent();
// 打开蓝牙服务器socket接口
Thread thread = new Thread( this );
thread.start();
}
catch (BluetoothStateException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
public void disconnect()
{
//断开接口,不再响应连接请求
done = true;
try {
// 打断server.acceptAndOpen()使之停止
server.close();
}
catch (IOException ex) {
}
// 停止终结点的发送和读取线程
// 并发送结束信号给其他连接
for ( int i=0; i < endPoints.size(); i++ )
{
EndPoint endpt = (EndPoint) endPoints.elementAt( i );
endpt.putString( NetLayer.SIGNAL_TERMINATE, "end" );
endpt.sender.stop();
endpt.reader.stop();
}
}
public void query()
{
try {
// 这里只检取最新的设备,而不查询已有的
agent.startInquiry(DiscoveryAgent.GIAC, new Listener());
}
catch (BluetoothStateException e)
{
e.printStackTrace();
}
}
//通过设备查询终结点
public EndPoint findEndPointByRemoteDevice( RemoteDevice rdev )
{
for ( int i=0; i < endPoints.size(); i++ )
{
EndPoint endpt = (EndPoint) endPoints.elementAt( i );
if ( endpt.remoteDev.equals( rdev ) )
{
return endpt;
}
}
return null;
}
//通过id查询终结点
public EndPoint findEndPointByTransId( int id )
{
for ( int i=0; i < pendingEndPoints.size(); i++ )
{
EndPoint endpt = (EndPoint) pendingEndPoints.elementAt( i );
if ( endpt.transId == id )
{
return endpt;
}
}
return null;
}
/**
* 发送消息给所有活动接点
* @param s
*/
public void sendString( String s )
{
for ( int i=0; i < endPoints.size(); i++ )
{
EndPoint endpt = (EndPoint) endPoints.elementAt( i );
endpt.putString( NetLayer.SIGNAL_MESSAGE, s );
}
}
/**
* 删除接点
* 该方法由远程设备从网络中删除时触发该方法(This is triggered by a remote EndPoint leaving the network)
* @param endpt
*/
public void cleanupRemoteEndPoint( EndPoint endpt )
{
endpt.reader.stop();
endpt.sender.stop();
// 从活动终结点列表中移除该接点
endPoints.removeElement( endpt );
}
public void run()
{
//连接到远程设备
StreamConnection c = null;
try
{
// 创建一个服务连接, using a
// Serial Port Profile URL syntax and our specific UUID
// and set the service name to BlueChatApp
server = (StreamConnectionNotifier)Connector.open(
"btspp://localhost:" + uuid.toString() +";name=BlueChatApp");
// Retrieve the service record template
ServiceRecord rec = localDevice.getRecord( server );
// set ServiceRecrod ServiceAvailability (0x0008) attribute to indicate our service is available
// 0xFF indicate fully available status
// This operation is optional
rec.setAttributeValue( 0x0008, new DataElement( DataElement.U_INT_1, 0xFF ) );
// Set the Major Service Classes flag in Bluetooth stack.
// We choose Object Transfer Service
rec.setDeviceServiceClasses(
SERVICE_TELEPHONY );
} catch (Exception e)
{
e.printStackTrace();
}
while( !done)
{
try {
c = server.acceptAndOpen();
// retrieve the remote device object
RemoteDevice rdev = RemoteDevice.getRemoteDevice( c );
//
// check to see if the EndPoint already exist
EndPoint endpt = findEndPointByRemoteDevice( rdev );
if ( endpt != null )
{
// 为了确保以前没有该客户端如果有则忽略该连接
} else
{
//否则新建一个接点并且打开发送接受线程
endpt = new EndPoint( this, rdev, c);
Thread t1 = new Thread( endpt.sender );
t1.start();
Thread t2 = new Thread( endpt.reader );
t2.start();
// 添加该结点
endPoints.addElement( endpt );
}
}
catch (IOException e) {
e.printStackTrace();
// 如果有任何异常, 则推断连接失败
// failed and close it. closing the connection will cause
// the reader and sender thread to exit (because they will got
// exception as well).
if (c != null)
try {
c.close();
}
catch (IOException e2) {
}
}
finally {
}
}
}
class Listener implements DiscoveryListener
{
/**
* 当一个设备被发现时,把它放入未决的终结点列表中
* 当所有的设备搜索完后将进行服务搜索
* A service search will happen when all the qualifying devices are discovered.
*
* @param remoteDevice
* @param deviceClass
*/
public void deviceDiscovered(RemoteDevice remoteDevice,
DeviceClass deviceClass)
{
try
{
EndPoint endpt = new EndPoint(NetLayer.this, remoteDevice, null);
pendingEndPoints.addElement( endpt );
} catch (Exception e)
{
e.printStackTrace();
}
}
public void inquiryCompleted(int transId)
{
// wait 100ms and start doing service discovery
// the choice of 100ms is really just a guess
timer.schedule( new DoServiceDiscovery(), 100 );
}
/**
* a service is discovered from a remote device.
* when a BlueChat service is discovered, we establish a connection to
* this service. This signal joining the existing virtual chat room.
* @param transId
* @param svcRec
*/
public void servicesDiscovered(int transId, ServiceRecord[] svcRec)
{
try {
for ( int i=0; i< svcRec.length; i++ )
{
EndPoint endpt = findEndPointByTransId( transId );
serviceRecordToEndPoint.put( svcRec[i], endpt );
}
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* service discovery is completed.
* @param int0
* @param int1
*/
public void serviceSearchCompleted(int transID, int respCode)
{
for ( Enumeration records = serviceRecordToEndPoint.keys(); records.hasMoreElements(); )
{
try {
ServiceRecord rec = (ServiceRecord) records.nextElement();
// We make an assumption that the first service is BlueChat. In fact, only one
// service record will be found on each device.
// Note: we know the found service is BlueChat service because we search on specific UUID,
// this UUID is unique to us.
String url = rec.getConnectionURL( ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false );
StreamConnection con = (StreamConnection)Connector.open( url );
// retrieve the pending EndPoint and initialize the necessary member variables
// to activate the EndPoint. this includes
// - initialize connection
// - start sender and reader thread
EndPoint endpt = (EndPoint) serviceRecordToEndPoint.get( rec );
if ( endpt != null )
{
endpt.con = con;
Thread t1 = new Thread( endpt.sender );
t1.start();
Thread t2 = new Thread( endpt.reader );
t2.start();
endPoints.addElement( endpt );
// once a EndPoint established, the BlueChat client is responsible to initiate the
// handshake protocol.
endpt.putString( NetLayer.SIGNAL_HANDSHAKE, localName );
} else
{
}
} catch (Exception e)
{
e.printStackTrace();
}
} // for
// finished process current batch of service record
// clear it and service discovery on next device
serviceRecordToEndPoint.clear();
synchronized( lock )
{
// unlock to proceed to service search on next device
// see DoServiceDiscovery.run()
lock.notifyAll();
}
}
} // inner class Listener
class DoServiceDiscovery extends TimerTask
{
public void run()
{
//对每个结点搜索服务
for (int i = 0; i < pendingEndPoints.size(); i++)
{
EndPoint endpt = (EndPoint) pendingEndPoints.elementAt(i);
try {
//
// searchServices return a transaction id, which we will used to
// identify which remote device the service is found in our callback
// listener (class Listener)
//<div></div>
// note: in theory, only one runtine instance of Listener is needed
// to handle all discovery callback. however, there is a bug in rococo
// simualtor that cause callback fails with one instance of used
// so we make a new Listener for every searchServices()
endpt.transId = agent.searchServices(null // null to indicate retrieve default attributes
,
new UUID[] { uuid } // BlueChat service UUID SerialPort
,
endpt.remoteDev,
new Listener());
// wait until the above service discovery is completed
// because N6600 cannot handle more than one service discovery
// request at the same time
// see serviceSearchCompleted()
synchronized( lock )
{
try {
lock.wait();
}
catch (InterruptedException ex) {
}
}
}
catch (BluetoothStateException e) {
e.printStackTrace();
}
} // for
// 所有服务都发现时,将删除列表中所有的结点
pendingEndPoints.removeAllElements();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -