📄 client.java
字号:
/*
*客户端
*作者:肖昶
*
*/
package fivegame;
import java.io.*;
import java.util.Vector;
import javax.bluetooth.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
public class Client extends Form implements CommandListener, Runnable,
DiscoveryListener {
private Vector devices = null;// 设备列表
private Vector services = null;// 服务列表
private int transIDs[] = null;// 用来存放搜索到的每个设备的服务搜索transaction ID
private StreamConnection conn = null;// 连接
private DataOutputStream dos = null;// 输出流
private DataInputStream dis = null;// 输入流
private DiscoveryAgent da = null;// 本地设备代理
private ChoiceGroup cgHosts = null;// 所有服务主机列表
private static final UUID serviceUUID = new UUID(
"da822f1b1b4d40c397c36286c753de77", false);// 服务唯一标识
private Command connectCmd = null;// 连接命令
private Command backCmd = null;// 返回命令
public static Client instance = null;// 本类自身实例
private static Thread tClient = null;// 引用本类主体线程(本类继承至Runnable可以向上转型至Thread)
private static ConnectThread connectThread = null;// 连接线程
// 构造函数
public Client() {
super("客户端");
devices = new Vector(10);// 设备列表
services = new Vector(10);// 服务列表
backCmd = new Command("返回", 2, 1);
addCommand(backCmd);
setCommandListener(this);
}
// 主线程,用来搜索服务
public synchronized void run() {
Gauge gauge = new Gauge("开始搜索蓝牙设备...", false, -1, 2);
append(gauge);// 提示滚动条
boolean isBTReady = false;// 本地设备代理是否就绪
try {
LocalDevice localdDevice = LocalDevice.getLocalDevice();// 获取本地设备
da = localdDevice.getDiscoveryAgent();// 获取本地设备代理
isBTReady = true;// 本地设备代理就绪
} catch (Exception e) {
e.printStackTrace();
}
if (!isBTReady) {// 本地设备代理未就绪
instance = null;
System.gc();
Alert refuseInfo = new Alert("错误", "蓝牙不可用!", null, AlertType.INFO);
FiveGame.display.setCurrent(refuseInfo, SelectList.getInstance());
return;
}
// 开始搜索设备
try {
da.startInquiry(DiscoveryAgent.GIAC, this);// 开始搜索设备,搜索到设备时自动调用deviceDiscovered(RemoteDevice,DeviceClass)函数
// 搜索完毕后将自动调用inquiryCompleted(int)函数
} catch (BluetoothStateException e) {
e.printStackTrace();
}
try {
wait();// 阻塞,等待设备搜索完毕
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("搜索设备等待中断");
}
if (devices.size() == 0) {// 未发现任何设备
instance = null;
System.gc();
Alert refuseInfo = new Alert("搜索失败", "没有找到蓝牙设备!", null,
AlertType.INFO);
FiveGame.display.setCurrent(refuseInfo, SelectList.getInstance());
return;
}
append("蓝牙设备搜索完毕,共找到:" + devices.size() + "个蓝牙设备...\n下面开始搜索服务...\n");
// 开始搜索服务
UUID uuidSet[] = new UUID[2];// 用于搜索的UUID集合
uuidSet[0] = new UUID(0x1101);// 搜索serial port protocol的服务
uuidSet[1] = serviceUUID;// 搜索指定的服务
transIDs = new int[devices.size()];// 用来存放搜索到的每个设备的服务搜索transaction ID
for (int i = 0; i < devices.size(); i++) {
RemoteDevice rd = (RemoteDevice) devices.elementAt(i);// 对每一个找到的设备
try {
transIDs[i] = da.searchServices(null, uuidSet, rd, this);// 开始搜索服务,搜索到服务时自动调用servicesDiscovered(int,ServiceRecord[])函数
// 搜索完毕后将自动调用serviceSearchCompleted(int, int)函数
} catch (BluetoothStateException e) {
e.printStackTrace();
}
}
try {
wait();// 阻塞,等待服务搜索完毕
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("搜索服务等待中断");
}
// 服务搜索完毕
if (services.size() == 0) {// 未找到任何服务
instance = null;
System.gc();
Alert refuseInfo = new Alert("搜索失败", "没有找到任何服务!", null,
AlertType.INFO);
FiveGame.display.setCurrent(refuseInfo, SelectList.getInstance());
return;
}
append("服务搜索完毕,共找到:" + services.size() + "个服务...\n请选择服务...");
String hosts[] = new String[services.size()];// 提供服务的远程主机设备列表
for (int i = 0; i < services.size(); i++) {
try {
hosts[i] = ((RemoteDevice) devices.elementAt(i))
.getFriendlyName(false);// 获取提供服务的远程主机设备列表
} catch (IOException e) {
e.printStackTrace();
}
}
delete(0);// 移除提示滚动条
cgHosts = new ChoiceGroup("服务器列表", 1, hosts, null);// 把可连接的主机以ChoiceGroup形式列出
connectCmd = new Command("连接", 4, 1);// 加入连接命令
append(cgHosts);
addCommand(connectCmd);
}
// 搜索到设备时该函数自动调用
public void deviceDiscovered(RemoteDevice rd, DeviceClass dc) {
if (devices.indexOf(rd) == -1)// 当前搜索到的设备没有被加入到设备集合中则加入
devices.addElement(rd);// 把当前搜索到的设备加入到设备集合中
}
// 设备搜索完毕后该函数将自动调用
public void inquiryCompleted(int arg0) {
synchronized (this) {
notify();// 唤醒线程继续运行run()接下来的代码
}
}
// 搜索到服务时该函数自动调用
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
for (int i = 0; i < servRecord.length; i++)
// 搜索到的是该设备所有指定服务的集合
services.addElement(servRecord[i]);// 加入服务集合中
}
// 服务搜索完毕后该函数将自动调用
public void serviceSearchCompleted(int transID, int arg1) {
for (int i = 0; i < transIDs.length; i++) {
if (transIDs[i] == transID) {// 符合这个条件说明该设备的服务已被搜索
transIDs[i] = -1;// 用来标志该设备设备的服务已被搜索
break;
}
}
boolean finished = true;// 标志所有设备的服务均已搜索完毕
for (int i = 0; i < transIDs.length; i++) {
if (transIDs[i] != -1) {// 有设备的服务还没有被搜索
finished = false;// 标志置为false
break;
}
}
if (finished)// 如果所有设备的服务均已搜索完毕
synchronized (this) {
notify();// 唤醒线程继续运行run()接下来的代码
}
}
// 命令动作响应, CommandListener接口必须实现的方法
public void commandAction(Command c, Displayable d) {
if (c == backCmd) {// 返回命令
da.cancelInquiry(this);// 取消搜索
if (tClient != null)
tClient.interrupt();// 若还在搜索则中断搜索线程
if (connectThread != null)
connectThread.interrupt();// 若正在连接则中断连接线程
try {// 关闭所有连接
if (dos != null)
dos.close();
if (dis != null)
dis.close();
if (conn != null)
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
instance = null;
System.gc();
FiveGame.display.setCurrent(SelectList.getInstance());
} else if (c == connectCmd) {// 连接命令
deleteAll();
append(new StringItem("提示:", "等待服务器回应..."));
removeCommand(connectCmd);// 连接命令
connectThread = new ConnectThread();// 连接线程
connectThread.start();// 开始连接
}
}
// 内部类,是用来连接目标主机的线程
private class ConnectThread extends Thread {
public void run() {
int i = cgHosts.getSelectedIndex();
ServiceRecord sr = (ServiceRecord) services.elementAt(i);// 目标服务
String url = sr.getConnectionURL(0, false);// 获取连接url
try {
conn = (StreamConnection) Connector.open(url);// 打开连接
dis = conn.openDataInputStream();// 打开数据输入
dos = conn.openDataOutputStream();// 打开数据输出
boolean authorized = dis.readBoolean();// 读取目标主机发回的认证信息
if (authorized) {// 如果目标主机同意连接
conn.close();// 关闭
MainMenu.instance = null;
SelectList.instance = null;
System.gc();
// 通讯连接控制器初始化
ConnectionControler.initConnCtrl(dis, dos);
FiveGame.display.setCurrent(MainGame.getInstance(false));// 转至游戏画面,false标识是以客户端方式进入
} else {// 目标主机拒绝连接
// 关闭所有连接
dos.close();
dis.close();
conn.close();
instance = null;
System.gc();
Alert refuseInfo = new Alert("连接失败", "服务器拒绝,无法连接!", null,
AlertType.INFO);
FiveGame.display.setCurrent(refuseInfo, SelectList
.getInstance());
}
} catch (Exception e) {// 连接异常,包括服务器掉线或用户主动取消连接都会引发该异常
try {// 关闭所有连接
if (dos != null)
dos.close();
if (dis != null)
dis.close();
if (conn != null)
conn.close();
} catch (Exception e1) {
e1.printStackTrace();
}
instance = null;
System.gc();
Alert refuseInfo = new Alert("连接失败", "服务器不可用或被用户取消连接!", null,
AlertType.INFO);
FiveGame.display.setCurrent(refuseInfo, SelectList
.getInstance());
}
}
}
// 返回本类的实例
public static final Client getInstance() {
if (instance == null)
instance = new Client();
tClient = new Thread(instance);
tClient.start();// 开始搜索 ,调用主线程run()
return instance;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -