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