使用mina框架,开发基于tcp/ip协议的门禁设备

本文介绍了一种智能门禁设备的启动、控制与管理方式,包括设备的初始化、远程开关门操作及设备状态跟踪。通过构建客户端连接、实现门禁设备的远程控制,以及使用心跳包维护连接稳定性,确保了系统的可靠性和高效性。
package com.tyhuanledi.device;

public interface DoorDevice {
	/**
	 * 启动门
	 * v1.0 zhc 2016年1月13日下午2:33:16
	 * void
	 */
	public void startUp();

	/**
	 * 开门
	 * v1.0 zhc 2016年1月13日下午2:37:26
	 * @param ip
	 * @param port
	 * @param doorNo 门号
	 * void
	 */
	public void openDoor(String ip, int port, int doorNo);

	/**
	 * 关门
	 * v1.0 zhc 2016年1月13日下午2:37:40
	 * @param ip
	 * @param port
	 * @param doorNo 门号
	 * void
	 */
	public void closeDoor(String ip, int port, int doorNo);
}
package com.tyhuanledi.device.impl;

import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tyhuanledi.device.DoorDevice;
import com.tyhuanledi.device.codec.DoorDecoder;
import com.tyhuanledi.device.codec.DoorEncoder;
import com.tyhuanledi.device.entity.DoorCommand;
import com.tyhuanledi.device.filter.ReConnectionFilter;
import com.tyhuanledi.device.filter.SessionManagerFilter;
import com.tyhuanledi.device.handle.DoorHandle;
import com.tyhuanledi.device.manager.SessionManager;

public class DoorDevice implements DoorDevice {
	private Logger log = LoggerFactory.getLogger(DoorDevice.class);

	@Override
	public void startUp() {
		final IoConnector connector = new NioSocketConnector();// 创建客户端连接
		connector.setConnectTimeoutMillis(5 * 1000);// 设置连接超时5秒
		connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10 * 1000);// 设置读写空闲10秒
		connector.getFilterChain().addFirst("reconnection", new ReConnectionFilter());// 添加断线重连过滤器
		connector.getFilterChain().addAfter("reconnection", "sessionManager", new SessionManagerFilter());// 添加session管理过滤器
		connector.getFilterChain().addAfter("sessionManager", "codec",
				new ProtocolCodecFilter(new DoorEncoder(), new DoorDecoder()));// 添加编解码过滤器
		connector.setHandler(new DoorHandle());// 添加业务处理

		List<Map<String, Object>> list = getList();
		for(final Map<String, Object> map : list){
			try {
				new Thread(new Runnable() {
					@Override
					public void run() {
						start(connector, map.get("ip").toString(), (Integer)map.get("port"));//启动设备
					}
				}).start();
			
				Thread.sleep(1000);//睡眠1秒
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public void start(IoConnector connector, String ip, int port) {
		while (true) {
			try {
				log.debug("开始连接门禁【" + ip + ":" + port + "】。");
				ConnectFuture future = connector.connect(new InetSocketAddress(ip, port));// 开始连接
				future.awaitUninterruptibly();// 等待连接创建成功
				IoSession session = future.getSession();// 获取会话
				if (session.isConnected()) {//如果连接成功
					log.debug("连接门禁【" + ip + ":" + port + "】成功。");
					break;
				}
			} catch (Exception e) {
				try {
					e.printStackTrace();
					log.debug("连接门禁【" + ip + ":" + port + "】失败,5秒后重试。");
					Thread.sleep(5000);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
			}
		}
	}

	@Override
	public void openDoor(String ip, int port, int doorNo) {
		IoSession session = SessionManager.get(ip, port);
		session.write(DoorCommand.createOpenCommand(doorNo));
	}

	@Override
	public void closeDoor(String ip, int port, int doorNo) {
		IoSession session = SessionManager.get(ip, port);
		session.write(DoorCommand.createCloseCommand(doorNo));
	}
	
	public List<Map<String, Object>> getList(){
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("ip", "192.168.8.31");
		map.put("port", 8000);
		map.put("doorNo", 1);
		list.add(map);
		
		Map<String, Object> map2 = new HashMap<String, Object>();
		map2.put("ip", "192.168.8.32");
		map2.put("port", 8000);
		map2.put("doorNo", 1);
		list.add(map2);
		return list;
	}

	public static void main(String[] args) {
		DoorDevice door = new DoorDevice();
		door.startUp();
		while (true) {
			try {
				InputStream in = System.in;
				int readKey = in.read();
				if (readKey == 49) {
					door.openDoor("192.168.8.31", 8000, 1);
				}
				if (readKey == 50) {
					door.closeDoor("192.168.8.31", 8000, 1);
				}
				if (readKey == 52) {
					door.openDoor("192.168.8.32", 8000, 1);
				}
				if (readKey == 53) {
					door.closeDoor("192.168.8.32", 8000, 1);
				} 
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
package com.tyhuanledi.device.filter;

import java.net.InetSocketAddress;

import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tyhuanledi.device.impl.DoorDevice;

public class ReConnectionFilter extends IoFilterAdapter {
	private Logger log = LoggerFactory.getLogger(ReConnectionFilter.class);
	
	@Override
	public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception {
		InetSocketAddress address = (InetSocketAddress) session.getServiceAddress();
		String ip = address.getHostName();
		int port = address.getPort();
		session.close(true);
		log.debug("门禁【" + ip + ":" + port + "】连接异常,连接自动断开。");
		
		super.exceptionCaught(nextFilter, session, cause);
	}
	
	@Override
	public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) throws Exception {
		InetSocketAddress address = (InetSocketAddress) session.getServiceAddress();
		String ip = address.getHostName();
		int port = address.getPort();
		session.close(true);
		
		NioSocketConnector connector = (NioSocketConnector) session.getService();
		int bothIdleTime = connector.getSessionConfig().getBothIdleTime();
		log.debug("连接门禁【" + ip + ":" + port + "】连接超时"+bothIdleTime+"秒,连接自动断开。");
		
		super.sessionIdle(nextFilter, session, status);
	}
	
	@Override
	public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
		super.sessionClosed(nextFilter, session);
		
		final NioSocketConnector connector = (NioSocketConnector) session.getService();
		InetSocketAddress address = (InetSocketAddress) session.getServiceAddress();
		final String ip = address.getHostName();
		final int port = address.getPort();
		log.debug("门禁【" + ip + ":" + port + "】连接被关闭,5秒后重新连接。");
		
		try {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep(5 * 1000);
						new DoorDevice().start(connector, ip, port);//启动设备
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}).start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
package com.tyhuanledi.device.filter;

import java.net.InetSocketAddress;

import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IoSession;

import com.tyhuanledi.device.manager.SessionManager;

public class SessionManagerFilter extends IoFilterAdapter{
	@Override
	public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
		InetSocketAddress address = (InetSocketAddress) session.getServiceAddress();
		SessionManager.put(address.getHostName(), address.getPort(), session);
		super.sessionCreated(nextFilter, session);
	}
	
	@Override
	public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
		InetSocketAddress address = (InetSocketAddress) session.getServiceAddress();
		SessionManager.remove(address.getHostName(), address.getPort());
		super.sessionClosed(nextFilter, session);
	}
}
package com.tyhuanledi.device.codec;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tyhuanledi.device.entity.Door;
import com.tyhuanledi.device.entity.DoorCommand;

public class DoorDecoder extends CumulativeProtocolDecoder{
	private static final Logger log = LoggerFactory.getLogger(DoorDecoder.class);

	@Override
	protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
		//接受数据
		byte[] data = new byte[in.limit()];
		in.get(data);
//		log.debug("收到消息:" + ByteUtil.toHexStr(data));
		
		//校验数据
		boolean validate = DoorCommand.validate(data);
		if(!validate){
			log.debug("校验数据失败");
			Door Door = new Door();
			Door.setCommand((byte)0x00);
			return true;
		}
		
		//解析数据
		out.write(new Door(data));
		return true;
	}
}
package com.tyhuanledi.device.codec;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

public class DoorEncoder extends ProtocolEncoderAdapter {
//	private static final Logger log = LoggerFactory.getLogger(DoorEncoder.class);

	@Override
	public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
		byte[] data = (byte[]) message;
//		log.debug("发送消息:" + ByteUtil.toHexStr(data));
		IoBuffer buffer = IoBuffer.allocate(data.length);
		buffer.put(data);
		buffer.flip();
		out.write(buffer);
	}
}
package com.tyhuanledi.device.handle;

import java.net.InetSocketAddress;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tyhuanledi.device.entity.Door;
import com.tyhuanledi.device.entity.DoorCommand;

public class DoorHandle extends IoHandlerAdapter{
	private Logger log = LoggerFactory.getLogger(DoorHandle.class);
	
	@Override
	public void messageReceived(IoSession session, Object message) throws Exception {
		Door door = (Door) message;
		InetSocketAddress address = (InetSocketAddress) session.getServiceAddress();
		String ip = address.getHostName();
		int port = address.getPort();
		
		//如果是心跳指令
		if(door.getCommand() == DoorCommand.HEART){
			session.write(DoorCommand.createHeartCommand());
			return;
		}
		
		//如果是开门指令
		if(door.getCommand() == DoorCommand.OPEN){
			if(door.getData()[0] == DoorCommand.OPEN_SUCC){
				log.debug("门禁【" + ip + ":" + port + "】开门成功。");
				return;
			}
			
			log.debug("门禁【" + ip + ":" + port + "】开门失败。");
		}
		
		//如果是关门指令
		if(door.getCommand() == DoorCommand.CLOSE){
			if(door.getData()[0] == DoorCommand.OPEN_SUCC){
				log.debug("门禁【" + ip + ":" + port + "】关门成功。");
				return;
			}
			
			log.debug("门禁【" + ip + ":" + port + "】关门失败。");
		}
	}
}
package com.tyhuanledi.device.manager;

import java.util.HashMap;
import java.util.Map;

import org.apache.mina.core.session.IoSession;

public class SessionManager {
	private static final Map<String, IoSession> map = new HashMap<String, IoSession>();

	public static void put(String ip, int port, IoSession session) {
		map.put(ip + port, session);
	}
	
	public static void remove(String ip, int port) {
		map.remove(ip + port);
	}

	public static IoSession get(String ip, int port) {
		return map.get(ip + port);
	}
}
package com.tyhuanledi.device.entity;

import java.util.Arrays;

import com.tyhuanledi.util.ByteUtil;

public class Door {
	byte stx = 0x02;// 开始位 0x02
	byte rand = 0x00;// 随机数 保留
	byte command;// 指令
	byte address = 0x00;// 控制器地址 保留
	byte door;// 门编号 1-4
	byte lengthL; // 数据长度低位
	byte lengthH; // 数据长度高位
	byte[] data;//
	byte cs;// 校验
	byte etx = 0x03;// 结束 0x03

	public Door() {
		
	}
	public Door(byte[] data) {
		command = data[2];
		address = data[4];
		lengthL = data[5];
		lengthH = data[6];
		int dataLen = ByteUtil.getLength(lengthL, lengthH);
		if (dataLen > 0) {
			this.data = Arrays.copyOfRange(data, 7, 7 + dataLen);
		}
		cs = data[data.length - 2];
		etx = data[data.length - 1];
	}

	public byte getStx() {
		return stx;
	}

	public void setStx(byte stx) {
		this.stx = stx;
	}

	public byte getRand() {
		return rand;
	}

	public void setRand(byte rand) {
		this.rand = rand;
	}

	public byte getCommand() {
		return command;
	}

	public void setCommand(byte command) {
		this.command = command;
	}

	public byte getAddress() {
		return address;
	}

	public void setAddress(byte address) {
		this.address = address;
	}

	public byte getDoor() {
		return door;
	}

	public void setDoor(byte door) {
		this.door = door;
	}

	public byte getLengthL() {
		return lengthL;
	}

	public void setLengthL(byte lengthL) {
		this.lengthL = lengthL;
	}

	public byte getLengthH() {
		return lengthH;
	}

	public void setLengthH(byte lengthH) {
		this.lengthH = lengthH;
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		this.data = data;
	}

	public byte getCs() {
		return cs;
	}

	public void setCs(byte cs) {
		this.cs = cs;
	}

	public byte getEtx() {
		return etx;
	}

	public void setEtx(byte etx) {
		this.etx = etx;
	}
}
package com.tyhuanledi.device.entity;

import java.util.Arrays;

import com.tyhuanledi.util.ByteUtil;

public class DoorCommand {
	public static final byte HEART = 0x56;//心跳命令
	public static final byte OPEN = 0x2C;//开门命令
	public static final byte OPEN_SUCC = 0x06;//开门成功
	public static final byte CLOSE = 0x2E;//关门命令

	public static byte[] buildCommand(byte command, int doorNo, byte[] data) {
		if(data == null){
			data = new byte[0];
		}
		
		byte[] message = new byte[9 + data.length];
		message[0] = 0x02;
		message[1] = 0x00;
		message[2] = command;
		message[3] = 0x00;
		message[4] = (byte) doorNo;
		message[5] = ByteUtil.getLower(data.length);
		message[6] = ByteUtil.getHigh(data.length);
		if(data != null && data.length > 0){
			System.arraycopy(message, 7, data, 0, data.length);
		}
		message[message.length - 2] = getCs(Arrays.copyOfRange(message, 0, message.length - 2));
		message[message.length - 1] = 0x03;
		return message;
	}
	
	public static byte getCs(byte[] data){
		byte cs = 0;
		for(byte b : data){
			cs ^= b;
		}
		return cs;
	}

	public static byte[] createHeartCommand() {
		return buildCommand(HEART, 1, null);
	}

	public static Object createOpenCommand(int doorNo) {
		return buildCommand(OPEN, doorNo, null);
	}

	public static Object createCloseCommand(int doorNo) {
		return buildCommand(CLOSE, doorNo, null);
	}
	
	public static boolean validate(byte[] data){
		byte checkCode = getCs(Arrays.copyOfRange(data, 0, data.length - 2));
		byte checkCode1 = data[data.length - 2];
		return checkCode == checkCode1;
	}

}
package com.tyhuanledi.util;

public class ByteUtil {

	/**
	 * 获取高地位长度 v1.0 zhc 2016年1月13日下午3:30:01
	 * 
	 * @param lengthH
	 * @param LengthL
	 * @return int
	 */
	public static int getLength(byte lengthH, byte LengthL) {
		return lengthH << 8 | LengthL;
	}

	/**
	 * 获取高位 v1.0 zhc 2016年1月13日下午4:08:31
	 * 
	 * @param length
	 * @return byte
	 */
	public static byte getLower(int num) {
		return (byte) (num >> 8);
	}

	/**
	 * 获取低位 v1.0 zhc 2016年1月13日下午4:11:14
	 * 
	 * @param length
	 * @return byte
	 */
	public static byte getHigh(int num) {
		return (byte) (num & 0xff00);
	}

	public static String toHexStr(byte[] data) {
		final String HEX = "0123456789ABCDEF";
		StringBuilder sb = new StringBuilder(data.length * 2);
		for (byte b : data) {
			if(sb.length() > 0){
				sb.append(",");
			}
			sb.append(HEX.charAt((b >> 4) & 0x0f));
			sb.append(HEX.charAt(b & 0x0f));

		}

		return sb.toString();
	}
}


jar包:
log4j-1.2.17.jar
mina-core-2.0.9.jar
slf4j-api-1.7.12.jar
slf4j-log4j12-1.7.12.jar

配置文件:
log4j.properties

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值