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();
            }
        }
         
    }
     
}
java

相關文章
相關標籤/搜索