今天看到有人分享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. Parallel Database for OLTP and OLAP

    Parallel Database for OLTP and OLAP Just asurvey article on materials on parallel database products ...

  2. Concurrency and Application Design (一)

    在计算机发展的早期,单位工作时间的最高限额是一台计算机可以执行通过CPU的时钟速度确定.但是,随着技术的进步和处理器设计变得更紧凑,热等物理约束开始限制处理器的最高时钟速度.因此,芯片制造商寻找其它的 ...

  3. Unity -- 入门教程三

    进入这个页面,按编译器版本进行下载,我用的是2010,所以要下载这个. 安装就不用我教了,下面开始看我是如何导入Unity VS的. 点击Import之后我们会发现并没有发生什么,但是接下来我们按一下 ...

  4. Neutron网络入门

    Neutron是OpenStack核心项目之中的一个,提供云计算环境下的虚拟网络功能.Neutron的功能日益强大,并在Horizon面板中已经集成该模块.作为Neutron的核心开发人员之中的一个. ...

  5. Odoo MRP 实际成本

    Odoo MRP 8 对于 产成品并不支持 实际成本记账 本人开发了一个模块,支持此特性, 可以在 淘宝店铺 购买 https://item.taobao.com/item.htm?_u=85jr9d ...

  6. Odoo 运费

    模块delievery可以将运费Charge给客户     安装delivery模块                 Delivery method     在做订单的时候,选择相应的运输方法, 系统 ...

  7. nagios插件之登陆SBC监控电话数

    运行:sbc_calls_status_new auto_ssh_sbc_10_17.sh | auto_ssh_sbc_11_17.sh vi sbc_calls_status_new.c #inc ...

  8. Solaris 下解决上网问题以及远程登录问题

    解决乱码问题 参考文章 http://www.jb51.net/os/Solaris/1656.html solaris 显示乱码的解决方法 现象: 利用命令 : LANG=zh; export LA ...

  9. soapUI学习笔记---断言的小使用

    转自:http://www.cnblogs.com/duimianyoushan/p/4274791.html 以下示例在soapUI 4.5中进行.刚开始学soapUI的使用,记录下以免忘记 1.创 ...

  10. Java依照List内存储的对象的某个字段进行排序

    关键点:将List内存储的对象实现Comparable类.重写它的compareTo()方法就可以 Bean: package chc; public class StuVo implements C ...