package com.dy.rtuMw.server.forTcp; 
 | 
  
 | 
import java.util.*; 
 | 
import java.util.Map.Entry; 
 | 
  
 | 
import com.dy.common.mw.channel.tcp.TcpIoSessionAttrIdIsRtuAddr; 
 | 
import org.apache.mina.core.session.IoSession; 
 | 
  
 | 
import com.dy.rtuMw.server.ServerProperties; 
 | 
  
 | 
  
 | 
public class TcpSessionCache { 
 | 
     
 | 
    /** 
 | 
     * 用Hashtable而不用HashMap原因: 
 | 
     * Hashtable线程安全的 
 | 
     * HashMap线程不安全的 
 | 
     * 多线程对sessionTable读出或存入,可能产生异常 
 | 
     * TcpSessionCache是在多线程环境下运行 
 | 
     * 
 | 
     * 2023-12-19实测,发现Hashtable并不线程安全,所以应用了HashMap和synchronized 
 | 
     */ 
 | 
    private static HashMap<String, TcpSession> map = new HashMap<String, TcpSession>() ; 
 | 
  
 | 
  
 | 
    /** 
 | 
     * 得到信息 
 | 
     * @return 
 | 
     */ 
 | 
    public static Integer[] info(){ 
 | 
        Integer rtuTotalConnect = 0 ;//已经连接过中间件的RTU总数(包括在线与离线的) 
 | 
        Integer rtuTotalOnLine = 0 ;//在线RTU总数 
 | 
        Integer rtuTotalOffLine = 0 ;//离线RTU总数 
 | 
        synchronized (map){ 
 | 
            rtuTotalConnect = map.size() ; 
 | 
            Collection<TcpSession> col = map.values() ; 
 | 
            for(TcpSession se : col){ 
 | 
                if(se.ioSession.isConnected()){ 
 | 
                    rtuTotalOnLine ++ ; 
 | 
                }else{ 
 | 
                    rtuTotalOffLine ++ ; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        return new Integer[] {rtuTotalConnect, rtuTotalOnLine, rtuTotalOffLine} ; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 关闭所有网络连接 
 | 
     */ 
 | 
    public static void closeAllSessions(){ 
 | 
        synchronized (map){ 
 | 
            Collection<TcpSession> col = map.values() ; 
 | 
            for(TcpSession se : col){ 
 | 
                se.ioSession.closeNow() ; 
 | 
            } 
 | 
            map.clear(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 加入新的IoSession 
 | 
     * @param rtuAddr 
 | 
     * @param ioSession 
 | 
     */ 
 | 
    //public static void putNewTcpSession(String rtuAddr, String protocolName, Short protocolVersion, IoSession ioSession){ 
 | 
    public static void putNewTcpSession(String rtuAddr, IoSession ioSession){ 
 | 
        synchronized (map){ 
 | 
            TcpSession tcpSe = map.get(rtuAddr) ; 
 | 
            if(tcpSe == null){ 
 | 
                tcpSe = new TcpSession() ; 
 | 
                //tcpSe.protocolName = protocolName ; 
 | 
                //tcpSe.protocolVersion = protocolVersion ; 
 | 
                tcpSe.ioSession = ioSession ; 
 | 
                map.put(rtuAddr, tcpSe) ; 
 | 
            }else{ 
 | 
                tcpSe.ioSession = ioSession ; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 更新IoSession对应的rtuAddr 
 | 
     * @param oldRtuAddr 
 | 
     * @param newRtuAddr 
 | 
     * @param ioSession 
 | 
     */ 
 | 
    //public static void changeRtuAddr(String oldRtuAddr, String newRtuAddr, String protocolName, Short protocolVersion, IoSession ioSession){ 
 | 
    public static void changeRtuAddr(String oldRtuAddr, String newRtuAddr, IoSession ioSession){ 
 | 
        if(oldRtuAddr != null && newRtuAddr != null && !oldRtuAddr.equals(newRtuAddr)){ 
 | 
            synchronized (map){ 
 | 
                TcpSession tcpSe = map.get(oldRtuAddr) ; 
 | 
                if(tcpSe == null){ 
 | 
                    putNewTcpSession(newRtuAddr, ioSession) ; 
 | 
                }else{ 
 | 
                    map.remove(oldRtuAddr) ; 
 | 
                    map.put(newRtuAddr, tcpSe) ; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 得到TcpSession 
 | 
     * @param rtuAddr 
 | 
     * @return 
 | 
     */ 
 | 
    public static TcpSession getTcpSession(String rtuAddr){ 
 | 
        return map.get(rtuAddr) ; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 得到Tcp通信协议名称 
 | 
     * @param rtuAddr 
 | 
     * @return 
 | 
     * */ 
 | 
    public static Object[] getTcpProtocolNameVersion(String rtuAddr){ 
 | 
        TcpSession tcpSe = map.get(rtuAddr) ; 
 | 
        if(tcpSe != null){ 
 | 
            return new Object[]{ 
 | 
                    tcpSe.ioSession.getAttribute(TcpIoSessionAttrIdIsRtuAddr.sessionArrProtocolName), 
 | 
                    tcpSe.ioSession.getAttribute(TcpIoSessionAttrIdIsRtuAddr.sessionArrProtocolVersion)}; 
 | 
        }else{ 
 | 
            return null ; 
 | 
        } 
 | 
    } 
 | 
  
 | 
  
 | 
    /** 
 | 
     * 得到所有在线与离线数量统计 
 | 
     * @return [0]=在线数量,[1]上线过,但当前离线的数量 
 | 
     */ 
 | 
    public static Integer[] allOnLineStateStatistics(){ 
 | 
        synchronized (map){ 
 | 
            Integer[] arr = new Integer[]{0, 0} ; 
 | 
            Iterator<Entry<String, TcpSession>> it = map.entrySet().iterator() ; 
 | 
            Entry<String, TcpSession> entry = null ; 
 | 
            while(it.hasNext()){ 
 | 
                entry = it.next() ; 
 | 
                if(entry.getValue().ioSession.isConnected()){ 
 | 
                    arr[0]++ ; 
 | 
                }else{ 
 | 
                    arr[1]++ ; 
 | 
                } 
 | 
            } 
 | 
            return arr ; 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 得到所有在线情况 
 | 
     * @return 
 | 
     */ 
 | 
    public static HashMap<String, Boolean> allOnLine(){ 
 | 
        synchronized (map){ 
 | 
            HashMap<String, Boolean> map = new HashMap<String, Boolean>(); 
 | 
            Iterator<Entry<String, TcpSession>> it = TcpSessionCache.map.entrySet().iterator() ; 
 | 
            Entry<String, TcpSession> entry = null ; 
 | 
            while(it.hasNext()){ 
 | 
                entry = it.next() ; 
 | 
                map.put(entry.getKey(), entry.getValue().ioSession.isConnected()) ; 
 | 
            } 
 | 
            return map ; 
 | 
        } 
 | 
    } 
 | 
  
 | 
  
 | 
    /** 
 | 
     * 得到部分在线情况 
 | 
     * @return 
 | 
     */ 
 | 
    public static HashMap<String, Boolean> partOnLine(String[] rtuAddrArrGrp){ 
 | 
        synchronized (map){ 
 | 
            HashMap<String, Boolean> map = new HashMap<String, Boolean>(); 
 | 
            for(String rtuAddr : rtuAddrArrGrp){ 
 | 
                TcpSession tcpSe = TcpSessionCache.map.get(rtuAddr) ; 
 | 
                if(tcpSe != null){ 
 | 
                    map.put(rtuAddr, tcpSe.ioSession.isConnected()) ; 
 | 
                } 
 | 
            } 
 | 
            return map ; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 网络是否连接 
 | 
     * @param rtuAddr 
 | 
     * @return 
 | 
     */ 
 | 
    public static Boolean isConnect(String rtuAddr){ 
 | 
        TcpSession tcpSe = map.get(rtuAddr) ; 
 | 
        if(tcpSe != null){ 
 | 
            return tcpSe.ioSession.isConnected() ; 
 | 
        } 
 | 
        return null ; 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 通过IoSession输出数据 
 | 
     * @param rtuAddr 
 | 
     * @param data 
 | 
     * @throws Exception 
 | 
     */ 
 | 
    public static void write(String rtuAddr, byte[] data) throws Exception{ 
 | 
        TcpSession tcpSe = map.get(rtuAddr) ; 
 | 
        if(tcpSe != null){ 
 | 
            if(tcpSe.ioSession.isConnected()){ 
 | 
                tcpSe.ioSession.write(data) ; 
 | 
            }else{ 
 | 
                throw new Exception("Rtu连接已经关闭!") ; 
 | 
            } 
 | 
        }else{ 
 | 
            throw new Exception("Rtu未曾上线!") ; 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 当有上行数据时 
 | 
     * @param rtuAddr 
 | 
     */ 
 | 
    public static void whenUpData(String rtuAddr){ 
 | 
        TcpSession tcpSe = map.get(rtuAddr) ; 
 | 
        if(tcpSe != null){ 
 | 
            tcpSe.lastDownComTime = 0L ;//置0,使等待lastUpDataTimeLive(见config.xml配置文件)时长后,即刻下发缓存中的命令 
 | 
            tcpSe.lastUpDataTime = System.currentTimeMillis() ; 
 | 
            tcpSe.lastUpDataTimeForOnlineCtrl = System.currentTimeMillis() ; 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 更新上行数据时刻 
 | 
     * 当上行数据时刻已经过去一定时长,上行数据时刻清空 
 | 
     * 当一定时间内没有上行数据,则认为RTU离线 
 | 
     */ 
 | 
    public static void updateRtuStatus(Long now){ 
 | 
        synchronized (map){ 
 | 
            Set<Map.Entry<String, TcpSession>> entrySet = map.entrySet() ; 
 | 
            Iterator<Map.Entry<String, TcpSession>> it = entrySet.iterator() ; 
 | 
            Map.Entry<String, TcpSession> entry ; 
 | 
            TcpSession tcpSe ; 
 | 
            while(it.hasNext()){ 
 | 
                entry = it.next() ; 
 | 
                tcpSe = entry.getValue(); 
 | 
                if(tcpSe.lastUpDataTime != null){ 
 | 
                    if(now - tcpSe.lastUpDataTime > ServerProperties.lastUpDataTimeLive){ 
 | 
                        tcpSe.lastUpDataTime = null ; 
 | 
                    } 
 | 
                } 
 | 
                if(tcpSe.lastUpDataTimeForOnlineCtrl != null){ 
 | 
                    if(tcpSe.ioSession != null && tcpSe.ioSession.isConnected()){ 
 | 
                        if(now - tcpSe.lastUpDataTimeForOnlineCtrl > ServerProperties.disconnectedByNoUpDataMinutes){ 
 | 
                            tcpSe.ioSession.closeNow() ; 
 | 
                            RtuLogDealer.log(entry.getKey(), "因较长时间未收上行数据,认为设备离线"); 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
} 
 |