Java 使用Socket 实现基于DTU的TCP服务器 + 数据解析 + 心跳检测

在物联网时代,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;
	}

	
}

结束语,以上只是我项目中的一些想法,提供的代码示例并不完整,如果需要可以和我一起探讨。欢迎给出意见。

  • 17
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 62
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 62
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值