package com.xxx.eterm;
import java.io.BufferedInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer;
public class ReadThread extends Thread {
private BufferedInputStream in = null;
ByteBuffer buffer = ByteBuffer.allocate(1024);
public ReadThread(BufferedInputStream in) { this.in = in; }
@Override public void run() {
// 登录特殊:发送01 A2..,返回00 14..,前两个字节就是总长度 // 以下是第3和4字节是总长度 // 心跳:发送01 FB 00 05 00 ,返回01 FA 00 05 00 // 未知命令:发送01 FE 00 11..,返回01 FD 00 06 .. // 未知命令:发送01 F9 00 44..,返回01 00 00 1A.. // 看票号:发送01 00 00 2B..,返回01 00 02 73..
byte[] data = new byte[64]; int readLength = 0; try { while (in != null && (readLength = in.read(data)) != -1) {
// 有效数据,写入buffer byte[] temp = new byte[readLength]; System.arraycopy(data, 0, temp, 0, readLength); buffer.put(temp);
// 解析数据Frame parseFrame();
} } catch (IOException e) { e.printStackTrace(); } System.out.println("end read."); }
private void parseFrame() {
// 设置当前位置为数据结束位置,指针指向0 buffer.flip();
// 可能有多个消息 while (buffer.limit() > 4) {
// 如果是指定的消息头 if (buffer.get(0) == (byte) 0x01 && buffer.get(1) == (byte) 0xFA || buffer.get(0) == (byte) 0x01 && buffer.get(1) == (byte) 0xFD || buffer.get(0) == (byte) 0x01 && buffer.get(1) == (byte) 0x00) { int dataLength = buffer.get(2) * 256 + buffer.get(3); if (buffer.limit() >= dataLength) {
// 把消息拆出来 byte[] msg = new byte[dataLength]; buffer.position(0); buffer.get(msg, 0, dataLength); // 从buffer的当前位置读取数据,指针会移动
// 放到队列 MsgCenter.putMsg(msg);
// 压缩缓存 buffer.compact(); // limit重置为容量最大值,指针指向数据最后,可以继续写入数据 buffer.flip(); // 设置当前位置为数据结束位置,指针指向0
// 继续while循环,解析下一个消息 } else { // 消息体不完整,继续接收数据 // 跳出while循环 buffer.position(0); buffer.compact();// limit重置为容量最大值,指针指向数据最后,可以继续写入数据 break; } } else { // 不是指定的消息头,丢弃 // 找到第一个0x01,之前的都丢弃。如果没找到,全部丢弃。 // 第一个0x01,可能是不想要的头,也得扔掉吧?那么就从下标1开始查找0x01 int p = -1; for (int i = 1; i < buffer.limit(); i++) { if (buffer.get(i) == (byte) 0x01) { p = i; break; } } if (p == -1) { buffer.clear(); break; // 跳出循环,继续接收数据 } else { buffer.position(p); buffer.compact(); buffer.flip(); // 设置当前位置为数据结束位置,指针指向0 // 继续while循环,解析下一个消息 } } } if (buffer.limit() <= 4) { buffer.position(0); buffer.compact();// limit重置为容量最大值,指针指向数据最后,可以继续写入数据 }
}
/** * 输出buffer内容. */ public void printBuffer(ByteBuffer buffer) {
// 记住当前位置 int p = buffer.position();
// 指针挪到0 buffer.position(0);
// 循环输出每个字节内容 for (int i = 0; i < buffer.limit(); i++) { byte b = buffer.get(); // 读操作,指针会自动移动 v(Integer.toHexString(b)); }
byte[] msg = new byte[buffer.limit()]; buffer.position(0); buffer.get(msg, 0, buffer.limit()); // 从buffer的当前位置读取数据,指针会移动 try { System.out.println(new String(msg, "GBK")); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); }
// 指针再挪回去 buffer.position(p);
// 本想用mark()和reset()来实现。 // 但是,它们貌似只能正向使用。 // 如,位置6的时候,做一下Mark, // 然后在位置10(位置要大于6)的时候,用reset就会跳回位置6.
// 而position(n)这个方法,如果之前做了Mark,但是Mark位置大于新位置,Mark会被清除。 // 也就是说,做了Mark后,只能向前跳,不能往回跳,否则Mark就丢失。 // rewind()方法,更干脆,直接清除mark。 // flip()方法,也清除mark // clear()方法,也清除mark // compact方法,也清除mark
// 所以,mark方法干脆不要用了,自己拿变量记一下就完了。 }
public void v(Object o) { System.out.println(o); } }
|