最近做了一个TCP连接android与单片机的项目。记录一下。
TCP连接对象
首先是TCP连接,以前没有做过,摘抄的同事项目中TCP连接对象。
public class TCPChannel {
private SocketChannel myChannel = null;
private boolean isConnecting = true;
private boolean isConnected = false;
// 发送心跳包的线程是否已经关闭
private boolean isSendHeartBreak = false;
private Selector selector = null;
private Iterator iterator;
private SelectionKey key;
private String mac = "";
private SocketAddress address;
private int timeOut;
private Thread heartbeat;
private int heartCunt = 0;
private boolean isWaitHeart = false;
public TCPChannel(SocketChannel socketChannel, SocketAddress address,
int timeOut) {
// TODO Auto-generated constructor stub
myChannel = socketChannel;
this.address = address;
this.timeOut = timeOut;
try {
LogUtil.e("selector open is will run open!!");
selector = Selector.open();
} catch (IOException e) {
LogUtil.e("Selector.open() is wrong XXXX");
e.printStackTrace();
}
}
public void connect() throws IOException, NullPointerException {
LogUtil.e("connect is be runned!!");
isConnecting = true;
isConnected = false;
System.out.println(myChannel.toString());
myChannel.configureBlocking(false);
if (selector == null)
throw new NullPointerException(mac);
myChannel.register(selector, SelectionKey.OP_CONNECT
| SelectionKey.OP_READ | SelectionKey.OP_WRITE);
myChannel.connect(address);
// System.out.println("检查TCP连接:" + checkConnect());
if (checkConnect()) {
LogUtil.e("checkConnect return true");
} else {
this.close();
LogUtil.e("checkConnect return false");
}
}
public void reConnect() {
Log.w("重练空调", "准备开始");
if (!isConnected) {
return;
}
isConnecting = true;
isConnected = false;
if (heartbeat != null) {
heartbeat.interrupt();
} else {
System.out.println("重连接时候心跳为空");
// sendHeartbeat();
}
try {
Log.w("重练空调", "关闭连接");
myChannel.socket().close();
myChannel.close();
selector.close();
myChannel = SocketChannel.open();
try {
selector = Selector.open();
} catch (IOException e) {
Log.e("----->", "Selector.open()错误2");
e.printStackTrace();
}
Log.w("重练空调", "正在重连");
try {
connect();
} catch (NullPointerException e) {
isConnected = true;
Log.e("----->", e + "抛出空指针异常33");
}
if (!isConnected) {
Log.w("重练空调", "没有连上");
close();
} else {
Log.w("重练空调", "重连成功");
Log.i("----->12.4", "重连成功?" + heartCunt + " "
+ isSendHeartBreak);
// 在断开wifi的情况下,心跳线程异常会从而终止,此判断是如果心跳因为异常而终止则重新开启心跳
if (heartCunt < 3) {
if (isSendHeartBreak) {
// sendHeartbeat();
}
} else {
close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ConcurrentModificationException e) {
e.printStackTrace();
close();
}
}
public boolean checkConnect() {
isConnected = false;
try {
Thread.sleep(timeOut * 1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
LogUtil.e("check TCP connection is:::-->" + myChannel
+ " " + myChannel.finishConnect()
+ " " + myChannel.isConnected());
if (myChannel != null && myChannel.finishConnect()
&& myChannel.isConnected()) {
LogUtil.e(" not null 重连的时候?");
isConnected = true;
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
isConnecting = false;
return isConnected;
}
public void send(byte[] bytes) {
// TODO Auto-generated method stub
if (!isConnected || isConnecting) {
return;
}
System.out.println("bytes " + bytes + "myChannel " + myChannel);
try {
ByteBuffer buf = ByteBuffer.wrap(bytes);
myChannel.write(buf);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int sendUpdateDate(byte[] bytes) {
// TODO Auto-generated method stub
if (!isConnected || isConnecting) {
return -1;
}
System.out.println("bytes " + bytes + "myChannel " + myChannel);
try {
ByteBuffer buf = ByteBuffer.wrap(bytes);
myChannel.write(buf);
return 0;
} catch (IOException e) {
e.printStackTrace();
return -2;
}
}
public void receive(Handler mainHandler) throws ParseException {
// LogUtil.e("in receive ...");
if (!isConnected || isConnecting) {
return;
}
// LogUtil.e("in receive 校验之后 ");
try {
selector.select(100);
if (selector != null && selector.isOpen()) {
// LogUtil.e("selector校验 selector != null && selector.isOpen()");
iterator = selector.selectedKeys().iterator();
} else {
return;
}
while (iterator.hasNext()) {
// LogUtil.e("进入while循环内, iterator.hasNext()");
key = iterator.next();
// LogUtil.e("key == "+key.toString());
// 删除正在处理的SelectionKey
iterator.remove();
// 如果该SelectionKey对应的Channel中有可读的数据
// 测试此键的通道是否已准备好接受新的套接字连接。
ServerSocketChannel server = null;
SocketChannel client = null;
if (key.isReadable()) {
LogUtil.e("key.isReadable() 为true了 有可读数据");
// 使用NIO读取Channel中的数据
SocketChannel sc = (SocketChannel) key.channel();
// ByteArrayOutputStream buff = new
// ByteArrayOutputStream(1024 );//缓冲
// ByteArrayOutputStream有toByteArray()方法 直接得到数据
ByteBuffer buff = ByteBuffer.allocate(256);
String content = "";
int i = 0;
// //161 23.97
while ((i = sc.read(buff)) > 0) {
sc.read(buff);
buff.flip();
byte[] bytes = new byte[i];
buff.get(bytes);
switch (i) {
case 97:// 1-46
BatteryInfo batteryInfo = SaveUtil
.saveBatteryInfo(bytes);
if(batteryInfo!=null){
Message msg = new Message();
Bundle b = new Bundle();// 存放数据
b.putSerializable("BatteryInfo",
(Serializable) batteryInfo);
msg.setData(b);
msg.what= 2;
LogUtil.e("发送数据97的、、、");
mainHandler.sendMessage(msg);
}
// 1.bytes,先截取前三个,后二个。留中间数据.返回三个数组
// 2。数据分开保存至bean中
// 2.1前三个直接把无符号byte转为int存储。
// 2.2中间数组两个合并一个,合并后,获取到short的无符号int值存储bean
// 2.2.1 数据格38-43四个合成一个转成long存储bean中。
// 2.3后两个变成16进制存储到CRC高低字节中。
// LogUtil.e(batteryInfo.toString());
break;
case 161:// 80-158
break;
case 25:// 60-69
BatteryWarmInfo saveBatteryWarmInfo = SaveUtil
.saveBatteryWarmInfo(bytes);
// LogUtil.e(saveBatteryWarmInfo.toString());
// 判断saveBatteryWarmInfo.警告信息集合长度,如果有数据,更新界面
if (saveBatteryWarmInfo.WarmInfos.size() > 0) {
// TODO发送消息到 MainUIThread 线程更新界面??
// mainHandler.
Message msg = new Message();
Bundle b = new Bundle();// 存放数据
b.putSerializable("warmInfos",
(Serializable) saveBatteryWarmInfo);
msg.setData(b);
msg.what= 1;
LogUtil.e("发送数据 25的、、、");
mainHandler.sendMessage(msg);
}
break;
default:
LogUtil.e("获取到未知长度数据!请复查代码");
break;
}
// for (int x = 0; x < i; x++) {
// LogUtil.e(Byte.toString(bytes[x]));
// }
buff.clear();
}
key.interestOps(SelectionKey.OP_READ);
if (i == -1) {
reConnect();
}
}
}
// LogUtil.e("跳出while循环, iterator.hasNext()");
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void close() {
isConnecting = true;
isConnected = false;
selector = null;
mac = null;
try {
myChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NullPointerException e) {
Log.w("TCP关闭", "空指针");
}
myChannel = null;
}
public String getMac() {
return mac;
}
public boolean isConnected() {
return isConnected;
}
// private void ProcessReply(String id, List strs) {
// JsonParser parser = new JsonParser();
// for (String str : strs) {
//
// System.out.println("str====:" + str);
// // 改用正则匹配
// if (str.matches("\{.*\}")) {
//
// System.out.println("没有问题啊!!!!!!!!!!!!!!!!");
//
// JsonElement jsonEl = parser.parse(str);
// JsonObject jsonObj = null;
// jsonObj = jsonEl.getAsJsonObject();
// JsonElement je;
// if ((je = jsonObj.get("response_type")) != null
// && je.getAsInt() == 2) {
// heartCunt = 0;
// isWaitHeart = false;
// } else {
// Control.receivedPackets(gApp, jsonObj, TCPChannel.this);
// }
// } else {
// System.out.println(id + "回码有问题啊!!!!!!!!!!!!!!!!" + str);
// GreeApplication.baseActivity.showToast(id + "局域网回码错误");
// }
// }
// }
// public void sendHeartbeat() {
// isSendHeartBreak = false;
// heartbeat = new Thread(mac + "心跳") {
// public void run() {
// while (isConnected && !isConnecting) {
// try {
// Log.i("心跳包",
// "心跳包发送"
// + mac
// + " "
// + JsonUtil.toJsonString(new Heartbeat(
// GreeTime.getTimestamp())));
//
// String heartPacket = JsonUtil
// .toJsonString(new Heartbeat(GreeTime
// .getTimestamp())); // 加密
//
// String key = GreeApplication.LANKeymap.get(mac);
// if (key == null) {
//
// key = "fbaef480";
// }
//
// try {
// heartPacket = Des.encryptDES(heartPacket, key,
// false);
// } catch (Exception e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
//
// System.out.println("=================心跳des加密:" + key);
// send(HeadUtil.addHead(heartPacket));
// isWaitHeart = true;
// sleep(10 * 1000);
// if (isWaitHeart && heartCunt++ > 1) {
// // 网络断开操作
// Log.i("心跳包", "心跳包检测到网络断开" + mac);
// reConnect();
// }
// } catch (UnsupportedEncodingException e) {
// Log.i("----->12.4", "1:heart error " + e.toString());
// isSendHeartBreak = true;
// e.printStackTrace();
// } catch (InterruptedException e) {
// Log.i("----->12.4", "2:heart error " + "num is "
// + heartCunt + " " + e.toString());
// isSendHeartBreak = true;
// e.printStackTrace();
// }
// }
// }
// };
// // ScheduledThreadPoolExecutor scheduler = new
// // ScheduledThreadPoolExecutor(1);
// // scheduler.schedule(heartbeat, 1,TimeUnit.SECONDS);
// heartbeat.start();
// }
// private void checkTiming() throws ParseException {
// // TODO Auto-generated method stub
// DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
// Locale.getDefault());
// Date _date = new Date();
//
// String time_str = df.format(_date);
//
// System.out.println("定时现在时间:" + time_str);
// if (AirCtrlDB.mPowerOnTimer != null) {
// if (AirCtrlDB.mPowerOnTimer.bTimerOn) {
// // System.out.println("//ON ");
// time_str = time_str.substring(0, 11)
// + AirCtrlDB.mPowerOnTimer.mHours + ":"
// + AirCtrlDB.mPowerOnTimer.mMin + ":00";
// long timeInterval = GreeTime.getInstance().timeIntervalNow(
// time_str);
// //
// Log.i("----->12.4","在定时开机的循环中:"+AirCtrlDB.mPowerOnTimer.mfireMode+" "+Math.abs(timeInterval));
// if (Math.abs(timeInterval) < 4000) {
//
// System.out.println("//on < 36 ");
// boolean _Execution = true;
// switch (AirCtrlDB.mPowerOnTimer.mfireMode) {
// case Timer_Mode_Once:
// AirCtrlDB.mPowerOnTimer.bTimerOn = false;
// break;
// case Timer_Mode_WorkDay:
// if (ByteOrder.getDay(_date) < 6) {
//
// } else {
// _Execution = false;
// }
// break;
// }
// if (_Execution) {
// // 开机
// Log.i("----->12.4", "开机");
// System.out.println("//on //开机 ");
// ByteOrder.setpoweronView();
// }
//
// }
//
// }
// }
//
// if (AirCtrlDB.mPowerOffTimer != null) {
// if (AirCtrlDB.mPowerOffTimer.bTimerOn) {
// // System.out.println("//Off ");
// /*
// * DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// * Date _date = new Date(); String time_str = df.format(_date);
// */
// time_str = time_str.substring(0, 11)
// + AirCtrlDB.mPowerOffTimer.mHours + ":"
// + AirCtrlDB.mPowerOffTimer.mMin + ":00";
// long timeInterval = GreeTime.getInstance().timeIntervalNow(
// time_str);
// //
// Log.i("----->12.4","在定时关机的循环中:"+AirCtrlDB.mPowerOffTimer.mfireMode+" "+Math.abs(timeInterval));
// if (Math.abs(timeInterval) < 4000) {
// System.out.println("//off < 36 ");
// boolean _Execution = true;
// switch (AirCtrlDB.mPowerOffTimer.mfireMode) {
// case Timer_Mode_Once:
// AirCtrlDB.mPowerOffTimer.bTimerOn = false;
// break;
// case Timer_Mode_WorkDay:
// if (ByteOrder.getDay(_date) < 6) {
//
// } else {
// _Execution = false;
// }
// break;
// }
//
// if (_Execution) {
// // 关机
// System.out.println("//off //关机 ");
// ByteOrder.setpowerOffView();
// }
// }
// }
// }
//
// }
}
此类的几个主要方法简单说明下:
1.TCPChannel(SocketChannel socketChannel, SocketAddress address,int timeOut)
初始化对象,SocketChannel,SocketAddress java api对象。
2.connect()
连接方法.内部调用了SocketChannel的register(selector, SelectionKey.OP_CONNECT| SelectionKey.OP_READ | SelectionKey.OP_WRITE);和connect(address);
3.reConnect()
重连socket,
4.send(byte[] bytes)
发送byte数组数据。
5.receiver();
数据接收。
调用方式:
先执行,接收数据的循环,接收到数据,就发送给主线程的handler
jieshou = new jieshou("TCP循环检测接收");
jieshou.start();
private class jieshou extends Thread {
public jieshou(String string) {
this.setName(string);
}
@Override
public void run() {
super.run();
LogUtil.e("接收线程run方法中 ");
while (true) {
try {
if (tcpChannel != null) {
tcpChannel.receive(mainHandler);
}
sleep(100);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
然后,连接通道,发送数据。
address = new InetSocketAddress(ipAddress, 8088);
flag = true;
// 建立TCP连接通道
thread = new Thread() {
public void run() {
try {
tcpChannel = new TCPChannel(SocketChannel.open(),
address, 2);
tcpChannel.connect();
while (flag) {
LogUtil.e("while true循环着 去请求数据。。。。");
try {
tcpChannel.send(getSendData(1, 46));
sleep(500);
tcpChannel.send(getSendData(60, 10));
sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
LogUtil.e("while 里抛出异常。");
}
}
LogUtil.e("tcp 请求数据,循环结束了。。。。。");
} catch (IOException e) {
e.printStackTrace();
}
}
};
thread.start();
断网后,重新连接:
if (tcpChannel != null)
tcpChannel.reConnect();
TCP连接就完毕了。之后是CRC16校验和byte数据处理。