package com.github.ompc.greys.core.server; import com.github.ompc.greys.core.util.LogUtil; import org.slf4j.Logger; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * 默认会话管理器实现 * Created by oldmanpushcart@gmail.com on 15/5/2. */ public class DefaultSessionManager implements SessionManager { private final Logger logger = LogUtil.getLogger(); // 5分钟 private static final long DURATION_5_MINUTE = 5L * 60 * 1000; // 会话超时时间 private static final long DEFAULT_SESSION_DURATION = DURATION_5_MINUTE; // 会话管理Map private final ConcurrentHashMap<Integer, Session> sessionMap = new ConcurrentHashMap<Integer, Session>(); // 会话ID序列生成器 private final AtomicInteger sessionIndexSequence = new AtomicInteger(0); private final AtomicBoolean isDestroyRef = new AtomicBoolean(false); public DefaultSessionManager() { activeSessionExpireDaemon(); } @Override public Session getSession(int sessionId) { return sessionMap.get(sessionId); } @Override public Session newSession(int javaPid, SocketChannel socketChannel, Charset charset) { final int sessionId = sessionIndexSequence.getAndIncrement(); final Session session = new Session(javaPid, sessionId, DEFAULT_SESSION_DURATION, socketChannel, charset) { @Override public void destroy() { super.destroy(); sessionMap.remove(sessionId); } }; final Session sessionInMap = sessionMap.putIfAbsent(sessionId, session); if (null != sessionInMap) { // 之前竟然存在,返回之前的 return sessionInMap; } return session; } /** * 激活会话过期管理守护线程 */ private void activeSessionExpireDaemon() { final Thread sessionExpireDaemon = new Thread("ga-session-expire-daemon") { @Override public void run() { while (!isDestroyRef.get() && !isInterrupted()) { // 间隔200ms检测一次 try { Thread.sleep(200); } catch (InterruptedException e) { interrupt(); } for (final Map.Entry<Integer, Session> entry : sessionMap.entrySet()) { final int sessionId = entry.getKey(); final Session session = entry.getValue(); if (null == session || session.isExpired()) { logger.info("session[{}] was expired", sessionId); if (null != session) { try { // 会话超时,关闭之前输出超时信息 session.getSocketChannel().write(ByteBuffer.wrap("Session timed out.\n".getBytes(session.getCharset()))); } catch (IOException e) { logger.debug("write expired message to session[{}] failed.", sessionId, e); } session.destroy(); } sessionMap.remove(sessionId); } } } } }; sessionExpireDaemon.setDaemon(true); sessionExpireDaemon.start(); } @Override public void clean() { // shutdown all the session for (Session session : sessionMap.values()) { session.destroy(); } sessionMap.clear(); logger.info("session manager clean completed."); } @Override public boolean isDestroy() { return isDestroyRef.get(); } @Override public void destroy() { if (!isDestroyRef.compareAndSet(false, true)) { throw new IllegalStateException("already destroy"); } clean(); logger.info("session manager destroy completed."); } }