zoukankan      html  css  js  c++  java
  • Java聊天室[长轮询]

    今天看到有人分享java实现的聊天室,想起很久以前还在热衷于java的时候也做过一个web聊天室,不拿出来晒晒,可能再也不为人知了,单纯是一个兴趣作品,稳定性不好,也没有考虑连接数和并发的问题,拿出来博大家一笑吧,项目我已改为maven管理;
         有一些没有修复的bug,比如SesseionManager 里的sessionCache 会只增不减等等,每一个用户一个Session实例,一个消息buffer(MessageQueue)来缓存未收到的消息,有SessionManager来管理,Dispatcher只是实现了 “广播”  消息,木有“多播”/“单播”,有兴趣的可以完善;下面是SessionManager,最长的一个代码文件了~,见笑了,用户下线是线程检查的,并不是很灵敏;
              ps:web聊天目前最简单的使用node.js的socket.io实现;
    ​1.图片

    2. [代码][Java]代码   
    package com.easyim.core;
     
    import java.util.Collection;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.ConcurrentHashMap;
     
    import com.easyim.util.EasyUtil;
    import com.easyim.util.Log;
     
    /**
     * Session 管理类(单例)
     * @author xl
     */
    public class SessionManager {
         
        /**
         * 缓存实例
         */
        private static SessionManager instance = null;
         
        /**
         * 存储session,Map<Session Id,Session>
         */
        private ConcurrentHashMap<String, Session>  sessions = new ConcurrentHashMap<String, Session>();
         
        /**
         * 计划任务,用于指定时间检查session是否有效
         */
        private Timer timer;
        private final long TIMER_INTERVAL_MILLIS = Config.getLongProperty(Protocol.TIMER_INTERVAL_MINS.toString())*1000;
        /**
         * SessionManager同步监视锁
         */
        private final Object lock = new Object();
         
         
        /**
         * 缓存sessions,防止检查时,无任何add/remove操作仍然遍历sessions
         */
        private Session[] sessionCache = new Session[0];
         
        /**
         * 是否重新缓存(自动设置)
         */
        private volatile boolean sessionCacheDirty = false;
         
        /**
         * 
         */
        protected SessionManager(){
             
        }
         
        /**
         * 获得SessionManager实例
         * @return
         */
        public static SessionManager getInstance(){
            if(instance==null){
                instance = new SessionManager();
            }
            return instance;
        }
         
        public Collection<Session> getSessions(){
            return sessions.values();
        }
         
        /**
         * 添加Session
         */
        public void addSession(Session session){
            sessions.put(session.getId(), session);
            sessionCacheDirty = true;
            Log.info("SessionManager add Session:"+session.getId()+",IP:"+session.getAddress());
        }
         
        /**
         * 获得Session
         * @param id Session Id
         * @return Session
         */
        public Session getSession(String id){
            return sessions.get(id);
        }
         
        /**
         * 指定id对应Session是否存在
         * @param id 指定Session Id
         * @return true/false
         */
        public boolean hasSession(String id){
            return sessions.containsKey(id);
        }
         
        /**
         * 移除并返回Session
         * @param session Session
         */
        public void removeSession(Session session){
            Session nsession = sessions.remove(session.getId());
            if(nsession!=null){http://www.bizhizu.cn/shouhui/
                Log.info("SessionManager remove Session:"+nsession.getId()+",IP:"+nsession.getAddress());
            }手绘图片
            sessionCacheDirty = true;
             
        }
        /**
         * sessions 长度
         * @return 长度
         */
        public int getSize(){
            return sessions.size();
        }
         
        /**
         * 遍历执行Seesion并调用ApplyMethod invoke执行
         * >>添加缓存支持
         * @param method
         */
        public void apply(ApplyMethod method){
    //          Iterator<Session> iterator = sessions.values().iterator();
    //          Session session = null;
    //          while (iterator.hasNext()) {
    //              session = iterator.next();
    //              try {
    //                  method.invoke(session);
    //              } catch (Exception e) {
    //                  Log.warn("SessionManager apply invoke 方法执行出错:"+e);
    //              }
    //          }
                //更新缓存
                if(sessionCacheDirty){
                    //TODO (easyim)sessionCache的只增不减...
                    sessionCache = sessions.values().toArray(sessionCache);
                    //设置状态为fasle,防止再次更新
                    sessionCacheDirty=false;
                }
                 
                //需要synchronized吗?
                 
                //遍历,传递给 method对象的invoke方法执行(必须从0开始遍历)
                for (int i = 0; i < sessionCache.length; i++) {
                    //为 null,退出循环
                    if(sessionCache[i]==null){
                        break;
                    }
                    try {
                        method.invoke(sessionCache[i]);
                    } catch (Exception e) {
                        Log.warn("SessionManager apply invoke 方法执行出错:",e);
                    }
                }
        }
         
        public void start(){
            if (timer!=null) {
                stop();
            }
            timer = new Timer(false);
            timer.schedule(new CheckTimerTask(), TIMER_INTERVAL_MILLIS, TIMER_INTERVAL_MILLIS);
            Log.info("CheckTimerTask started; interval=" + TIMER_INTERVAL_MILLIS + "ms");
             
        }
         
        public void stop(){
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
            sessions.clear();
            Log.info("CheckTimerTask stopped");
        }
         
        /**
         * apply 调用方法接口
         * @author xl
         *
         */
        public static interface ApplyMethod{
     
            public void invoke(Session session);
        }
         
        /**
         * 检查Session是否有效
         * @author xl
         *
         */
        private class CheckTimerTask extends TimerTask implements ApplyMethod{
             
            //private final long MAXWAITTIME_MILLIS = Config.getLongProperty(Protocol.MAXWAITTIME_MILLIS.toString());
             
            private long lastRun = EasyUtil.now();
            private long delta;
             
            @Override
            public void run() {
                long now = EasyUtil.now();
                //按理 delta>=TIMER_INTERVAL_MILLIS
                delta = now - lastRun;
                lastRun=now;
                getInstance().apply(this);
                if(Log.getLogger().isDebugEnabled()){
                    Log.debug("CheckTimerTask,时间:"+EasyUtil.dateFormat()+", sessions size:"+sessions.size()+" ,cache size:"+sessionCache.length);
                }
            }
     
            @Override
            public void invoke(Session session) {
                session.less(delta);
                if(session.isExpired()){
                    Log.info("CheckTimerTask: remove Session");
                    session.remove();
                }
            }
             
        }
         
    }

  • 相关阅读:
    二分、冒泡、选择、插入排序
    15行python代码,帮你理解令牌桶算法
    mybatis 的排序方式用参数传入 但是无法正常排序
    js事件篇
    ajax详解
    kafka概要设计
    HttpClient简述
    双十一问题:在洪峰数据来临的瞬间,redis出现连接超时异常
    双十一问题:kafka消费能力低下原因思考
    Timer类注意事项
  • 原文地址:https://www.cnblogs.com/xkzy/p/3920079.html
Copyright © 2011-2022 走看看