今天看到有人分享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