今天看到有人分享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聊天室[长轮询]的更多相关文章

  1. php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室)

    php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室) 一.总结 1.ajax长轮询和websocket都可以时间网络聊天室 ...

  2. 分享一个基于长连接+长轮询+原生的JS及AJAX实现的多人在线即时交流聊天室

    实现网页版的在线聊天室的方法有很多,在没有来到HTML5之前,常见的有:定时轮询.长连接+长轮询.基于第三方插件(如FLASH的Socket),而如果是HTML5,则比较简单,可以直接使用WebSoc ...

  3. 使用轮询&长轮询实现网页聊天室

    前言 如果有一个需求,让你构建一个网络的聊天室,你会怎么解决? 首先,对于HTTP请求来说,Server端总是处于被动的一方,即只能由Browser发送请求,Server才能够被动回应. 也就是说,如 ...

  4. 网页实时聊天之js和jQuery实现ajax长轮询

    众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...

  5. [转]网页实时聊天之js和jQuery实现ajax长轮询 PHP

    网页实时聊天之js和jQuery实现ajax长轮询 众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的 ...

  6. Web 通信 之 长连接、长轮询(转)

    Web 通信 之 长连接.长轮询(long polling) 基于HTTP的长连接,是一种通过长轮询方式实现"服务器推"的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强 ...

  7. Web 通信 之 长连接、长轮询(long polling)

    基于HTTP的长连接,是一种通过长轮询方式实现"服务器推"的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强了程序的实时性和交互性. 一.什么是长连接.长轮询? 用通俗易 ...

  8. Web 通信 之 长连接、长轮询(long polling)(转)

    基于HTTP的长连接,是一种通过长轮询方式实现"服务器推"的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强了程序的实时性和交互性. 一.什么是长连接.长轮询? 用通俗易 ...

  9. 长轮询和Comet

    长轮询方式是由前端定时发起AJAX请求,若请求到数据则把数据显示出来. comet方式是由客户端与服务器端发起一个长连接,然后客户端通过监听事件的方式,来对服务器端返回的数据作出响应和处理. 实时性要 ...

随机推荐

  1. spring事物,在service层如果进行了异常处理,则不会回滚

    今天进行了事物处理的验证,发现如果在在service层如果进行了异常处理,则不会回滚. 看来异常的处理还是统一放在controller层比较好,service如果是查询方法,出现了异常,就不要做处理了 ...

  2. maven项目对于maven远程仓库没有资源的解决办法

    下载资源到本地 方法一:dependency scope 是system 类型 <dependency> <groupId>edu.ucar</groupId> & ...

  3. Java基础教程:tutorialspoint-junit

    教程: 来自turorialspoint的JUnit教程(英文),官网:https://www.tutorialspoint.com/junit/index.htm 中文版本:http://wiki. ...

  4. javascript --- 对象之间的继承

    了解这一章之前,先把我们之前讲到的以构造函数创建对象为前提的继承抛到一边. 首先,我们先用一个var o = {}创建一个没有任何属性的空对象作为我们的‘画板’,然互在逐步向这个画板里添加属性,和方法 ...

  5. dubbo常见问题解答FAQ

    常见问题解答 1. 如果服务注册不上怎么办? 2. 出现RpcException: No provider available for remote service异常怎么办? 3. 出现调用超时co ...

  6. SilverLight:基础控件使用(5)-TreeView控件-基本使用

    ylbtech-SilverLight-Basic-Control:基础控件使用(5)-TreeView控件-基本使用 前台编辑 后台逐个添加 后台绑定数据源 1.A,返回顶部TreeView控件(树 ...

  7. Hierarchical data in postgres

    https://coderwall.com/p/whf3-a/hierarchical-data-in-postgres --------------------------------------- ...

  8. [Algorithm] JavaScript Graph Data Structure

    A graph is a data structure comprised of a set of nodes, also known as vertices, and a set of edges. ...

  9. Android 组件之Service解析

    原创文章,转载请注明 http://blog.csdn.net/leejizhou/article/details/50866875 李济洲的博客 Service是Android四大组件之中的一个.S ...

  10. 5.4 heapq--堆队列算法

    本模块实现了堆队列算法,也叫作优先级队列算法.堆队列是一棵二叉树.而且拥有这样特点,它的父节点的值小于等于不论什么它的子节点的值,假设採用数组array实现,能够把它们的关系表示为:heap[k] & ...