67,513
社区成员
发帖
与我相关
我的任务
分享
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.test.util.StaticConvert;
/**
* 数据接收线程
*/
public class ReceiveThread implements Runnable {
private Log logger = LogFactory.getLog(this.getClass());
private DataInputStream inStm = null;
private Socket socket;
private String fn = "数据接收";
public ReceiveThread(Socket socket, DataInputStream inStm) {
this.socket = socket;
this.inStm = inStm;
}
public void run() {
logger.info(fn+", 启动接收线程.");
boolean b =true;
while (b) {
try {
//处理前先等几秒
Thread.sleep(1000);
//1 连接是否正常
if(socket.isConnected()) {
ByteArrayInputStream bufIn2 = null;
ByteArrayOutputStream bufCache = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
byte[] bufbyte = null;
int netlen = -1;
int buflen = -1;
int tmplen = -1;
int datalen = -1;
byte[] begByte = null;
String hexStr1 = "";
String hexStr2 = "";
while ((netlen = inStm.read(bytes)) != -1) {
//合并上次一缓存数据 + 本次读取的数据
bufCache.write(bytes, 0, netlen);
//收到数据可能0包,1包,N包数据
boolean hisfra =true;
while (hisfra) {
//最少要4字节才处理
if(bufCache.size() <4) {
hisfra =false;
continue;
}
//取出上次缓存,然后清空缓存待用
buflen = bufCache.size();
bufbyte = bufCache.toByteArray();
bufCache.reset();
bufCache = null;
bufCache = new ByteArrayOutputStream();
//放入读取流中处理
bufIn2 = new ByteArrayInputStream(bufbyte, 0, buflen);
//取报文开头4字节内容
begByte = new byte[] {bufbyte[0], bufbyte[1], bufbyte[2], bufbyte[3]} ;
hexStr1 = StaticConvert.parseByte2HexStr(begByte, 4);//(代码自己写)
//a,报文以EB90EB90开头
if("EB90EB90".equals(hexStr1)) {
//数据前面的报文内容必须有规定的长度才能处理: 报文头+长度+类型 = 4+2+2=8
byte[] headByte = new byte[8];
if(buflen >=8) {
bufIn2.read(headByte, 0, 8);
//取长度数据(代码自己写)
datalen = StaticConvert.getBJXNYLenBy2ByteL(new byte[] {headByte[1],headByte[2]} );
//1) 刚好一包数据
if(datalen >0 && buflen == datalen){
hisfra =false;
//处理一包数据....
//2) 一包数据有多余
}else if(datalen >0 && buflen > datalen){
byte[] dataBytes = new byte[datalen];
//合并已读出的字节
System.arraycopy(headByte, 0, dataBytes, 0, 6);
//本报文其它字节
bufIn2.read(dataBytes, 6, datalen - headByte.length);
//处理一包数据....
//余下的字节: 如果是EB90EB90开头, 则放在缓存, 否则认为是无效数据.
byte[] bytes2 = new byte[bufIn2.available()];
tmplen = bufIn2.read(bytes2);
begByte = new byte[] {bytes2[0], bytes2[1], bytes2[2], bytes2[3]} ;
hexStr1 = StaticConvert.parseByte2HexStr(begByte, 4);//(代码自己写)
if("EB90EB90".equals(hexStr1)) {
bufCache.write(bytes2, 0, tmplen);
}else {
hisfra =false;
hexStr1 = StaticConvert.parseByte2HexStr(bytes2, tmplen);//(代码自己写)
hexStr2 = StaticConvert.parsePrintHexStr(hexStr1);//(代码自己写)
logger.info(fn+", 剩余无效报文: " + hexStr2);
}
}else {
hisfra =false;
//可变报文长度不够,则放入缓冲
bufCache.write(bufbyte, 0, buflen);
}
}else {
//可变报文长度不够,则放入缓冲
hisfra =false;
bufCache.write(bufbyte, 0, buflen);
}
//c,无效数据
}else {
hisfra =false;
hexStr1 = StaticConvert.parseByte2HexStr(bufbyte, buflen);//(代码自己写)
hexStr2 = StaticConvert.parsePrintHexStr(hexStr1);//(代码自己写)
logger.info(fn+", 收到无效报文: " + hexStr2);
}
//while
bufIn2.reset();
bufIn2 = null;
bufbyte = null;
}
}
}else {
b = false;
logger.info(fn+", 接收线程结束.");
}
} catch (IOException e) {
//
logger.error(fn+", 接收报文,网络异常.", e);
} catch (Exception e) {
logger.error(fn+", 接收线程异常.", e);
} finally {
}
}
socket = null;
inStm = null;
}
}
------------- 冻结数据请求报文分析-------------
索引:00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
报文:68 66 00 66 00 68 47 05 01 2f 00 68 00 06 2f 00 00 00 00 00 0c 06 13 00 00 00 10 0c 06 13 02 75 16
0-1, 共1字节, 起始字符(1 字节,68H) 68
1-3, 共2字节, 长度L(2 字节,只取D2-D15,D1-D0补10后值是0066) 66 00
3-5, 共2字节, 长度L2(重复,2 字节,只取D2-D15) 66 00
5-6, 共2字节, 起始字符(重复,1 字节,68H) 68
6-7, 共1字节, 控制域C(1 字节,47H) 47
7-11, 共4字节, 地址域A(4 字节) 05 01 2f 00
11-12,共1字节, 应用服务数据单元-类型标识(1 字节,64H) 68
12-13,共1字节, 应用服务数据单元-可变结构限定词(VSQ,1字节,00H) 00
13-14,共1字节, 应用服务数据单元-传送原因(1 字节,06H) 06
14-16,共2字节, 应用服务数据单元-公共地址(2 字节) 2f 00
16-23,共7字节, 应用服务数据单元-元公共描述-开始时间( 7 字节) 00 00 00 00 0c 06 13
23-30,共7字节, 应用服务数据单元-元公共描述-结束时间( 7 字节) 00 00 00 10 0c 06 13
30-31,共1字节, 应用服务数据单元-元公共描述-冻结周期( 1 字节) 02
31-32,len-2,共1字节, 校验和CS(1 字节,12->0C) 75
32-33,len-1,共1字节, 结束字符(1 字节,16H) 16
// 取前四位字节,算出此次请求的字节长度
byte[] lengthData = new byte[4];
int readCount = 0;
// 读取消息头
while (readCount < lengthData.length) {
readCount += inputStream.read(lengthData, readCount, lengthData.length - readCount);
if (readCount == -1) {
log.info("服务端断开1!");
return;
}
}
2、你的问题3和4是想知道是否连接正常。通常我会发送心跳包数据,可以自定义一个心跳包类型的数据,每隔多长时间发送一次,比如10s,如果说20s或者30s都没有收到此类数据,则判定断线,将socket关闭,如果是客户端此时可考虑断线重连。(其他的通过异常能处理到的那些是可以判定的)