在物联网时代,DTU的运用非常广泛 ;环境监测中通过DTU将传感器的数据远程传输至云服务器也是比较常见的用法。下面我来分享一下我的项目经验
1.物理连接拓扑
2.服务器后台流程
3.代码
设备TCP服务器监听线程
class SubRoutineThread implements Runnable{
private int port; //接收数据端口
private String proName; // 接收数据名称
private ParseData parseData; //解析数据对象
public SubRoutineThread(int port,String proName,ParseData parseData){
this.port=port;
this.proName=proName;
this.parseData=parseData;
}
public void run(){
SocketServer socketServer =new SocketServer();
try {
socketServer.start(port,proName,parseData);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void setPort(int port) {
this.port = port;
}
public void setProName(String proName) {
this.proName = proName;
}
public void setParseData(ParseData parseData) {
this.parseData = parseData;
}
}
开启监听与数据接收
/**
* TCP Server
* @author yz
*
*/
public class SocketServer {
private static Logger logger = Logger.getLogger(SocketServer.class);
private int port;
private ParseData parseData;
public String nameOfPro="";
public boolean outputConsole=false;
public void start(int port,String namePro, ParseData parseData) throws IOException {
this.port=port;
this.parseData=parseData;
this.nameOfPro=namePro;
ServerSocket serverSocket = new ServerSocket(port);
CommTool.printInfo(nameOfPro + " 正在监听,端口:"+String.valueOf(port));
while (true) {
Socket socket = serverSocket.accept();
new SocketThread(socket).start();
}
}
//数据处理线程
class SocketThread extends Thread {
private Socket socket;
private byte[] bytes;
public Date lastHeartPkDate = new Date();
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public SocketThread(Socket socket) {
this.socket = socket;
}
public void run() {
CommTool.printInfo(nameOfPro + " 接受连接:" + socket.getInetAddress() + ":" + socket.getPort());
try {
InputStream ins= socket.getInputStream();
while(true) {
if(DateUtils.pastSeconds(lastHeartPkDate) > 60 )
{
logger.info(nameOfPro+",长时间未收到心跳数据,停止接收数据并断开连接");
CommTool.printInfo(nameOfPro+",长时间未收到心跳数据,停止接收数据并断开连接");
break;
}
int readBytes = 0;
int length = 0;
//循环接收,保证接收完整数据包
ByteBuffer buffer = ByteBuffer.allocate(4096);
while(ins.available() > 0) {
byte[] temp = new byte[ins.available()];
length = ins.read(temp);
buffer.put(temp,readBytes,length);
readBytes += length;
}
bytes = buffer.array();
if(readBytes > 0) {
CommTool.printInfo(nameOfPro+",接收到数据," + readBytes + "bytes");
//解析 ,需要判定是否是心跳包
if(!parseData.parse(bytes)){
logger.info(nameOfPro+",接收数据解析失败");
CommTool.printInfo(nameOfPro+",数据解析失败");
return;
}
if(!parseData.isHeartPack()) {
//存储
if(!parseData.save()){
logger.info(nameOfPro+",数据存储失败");
CommTool.printInfo(nameOfPro+",数据存储失败");
return;
}
CommTool.printInfo(nameOfPro+",数据解析存储成功");
}
else {
lastHeartPkDate = parseData.getLastHeartPackDate();
}
}
}
} catch (Exception e) {
logger.error(nameOfPro+",未知错误,"+e.toString());
CommTool.printInfo(nameOfPro+",未知错误,"+e.toString());
} finally {
if (socket != null) {
if (!socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}
数据包解析接口类
/**
* 解析接口
* @author 70910
*
*/
public interface ParseData {
boolean parse(byte[] bytes);
boolean save();
void setDrcProInfo(DrcProInfo drcProInfo);
//是否是心跳包
boolean isHeartPack();
//获取最后心跳时间
Date getLastHeartPackDate();
}
设备数据包解析实体类
/**
* 解析负氧离子数据
* @author yangze
* 2019-08-21
*
*/
public class AnionSensorDataParse implements ParseData {
private static Logger logger = Logger.getLogger(AnionSensorDataParse.class);
public DrcProInfo drcProInfo;
private int deviAddr; //设备地址
private int funcCode; //功能码
private int dataLength; //数据长度
private int anionData;
private String typeOfPk;
private byte[] srcData;
private DeviceInfo deviceInfo = new DeviceInfo();
private Map<String, ParamInfo> name2ParamInfoMap= new HashMap<String, ParamInfo>();
private static Connection conn = null;
private boolean isHeartPk = false;
private Date lastHeartPkDate = new Date();
public AnionSensorDataParse(){}
@Override
public boolean parse(byte[] data){
srcData = Arrays.copyOfRange(data, 0, 9);
String preStr=drcProInfo.getParseDataName();
int indexNow=0;
if(是心跳包){
lastDataTime = new Date();
isHeartPk = true;
return true;
}
else if(是数据包){
isHeartPk = false;
//解析数据
return true;
}
else{
isHeartPk = false;
CommTool.printInfo(preStr+",数据包类型不正确");
logger.error(preStr+",数据包类型不正确");
return false;
}
}
@Override
public boolean isHeartPack() {
return this.isHeartPk;
}
@Override
public Date getLastHeartPackDate() {
return this.lastDataTime;
}
@Override
public boolean save() {
//连接数据库
//存储数据
return true;
}
@Override
public void setDrcProInfo(DrcProInfo drcProInfo) {
this.drcProInfo=drcProInfo;
}
}
结束语,以上只是我项目中的一些想法,提供的代码示例并不完整,如果需要可以和我一起探讨。欢迎给出意见。