zoukankan      html  css  js  c++  java
  • 用socketio做web系统在线用户量统计,和消息提醒

    一开始想用session监听器,不过有过期时间,并非实事。而且,如果不用jsp,就需要写个rest服务,供前段轮询调用接口,比如5秒一次,来刷新在线人数。影响性能。后来想到用WebSocket来做。刚好之前有用过socketio来推送消息,于是敲定方案。

    我使用的是开源库,https://github.com/mrniko/netty-socketio, 有近3000个star,还是不错的。

    因为业务上需求是跟进登录账号来统计,而对登录IP、浏览器不做区分,即同一个账号,无论在哪里登录,总数都算1.基于次,前端连接时只需把登录账号传到后台即可。

    1. 后台服务OnlineUserCounter.java:

    public class OnlineUserCounter {

    private static SocketIOServer socketServer = null;
    /**
    * 在线用户数
    */
    public static Set<String> userSet = new HashSet<>(500);
    private static JSONObject result = new JSONObject();
    /**
    * 客户端计数
    */
    public static AtomicInteger clientCount = new AtomicInteger();

    private static SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void startSocketIOServer() {
    try {
    Configuration config = new Configuration();
    InetAddress localHost;
    String localIp = "127.0.0.1";
    try {
    localHost = Inet4Address.getLocalHost();
    localIp = localHost.getHostAddress();
    } catch (Exception e) {
    ServiceLog.error(e);
    }
    String ip = AppHandle.getHandle(Constants.MODULE).getProperty("ONLINE_SERVER_IP", localIp);
    config.setHostname(ip);
    int port = Integer.parseInt(AppHandle.getHandle(Constants.MODULE)
    .getProperty("ONLINE_SERVER_PORT", "9092"));
    config.setPort(port);

    SocketConfig sockConfig = new SocketConfig();
    sockConfig.setReuseAddress(true);//解决SOCKET服务端重启"Address already in use"异常
    sockConfig.setTcpKeepAlive(false);
    config.setSocketConfig(sockConfig);

    socketServer = new SocketIOServer(config);
    socketServer.addConnectListener(new ConnectListener() {

    @Override
    public void onConnect(SocketIOClient client) {
    int count = clientCount.incrementAndGet();
    HandshakeData handshakeData = client.getHandshakeData();
    String userCode = handshakeData.getSingleUrlParam("userCode");
    ServiceLog.debug(userCode + " connet, total count:" + count);
    addUser(userCode);
    sendOnlineMessage();
    }
    });
    socketServer.addDisconnectListener(new DisconnectListener() {

    @Override
    public void onDisconnect(SocketIOClient client) {
    if(clientCount.get() > 0) {
    clientCount.decrementAndGet();
    }
    HandshakeData handshakeData = client.getHandshakeData();
    String userCode = handshakeData.getSingleUrlParam("userCode");
    ServiceLog.debug(userCode + " disconnet, total count:" + clientCount.get());
    removeUser(userCode, client);
    sendOnlineMessage();
    }
    });
    socketServer.addEventListener("HEARTBEAT_EVENT", String.class, new DataListener<String>(){

    @Override
    public void onData(SocketIOClient client, String data, AckRequest ackSender) throws Exception {
    JSONObject dataJson = JSON.parseObject(data);
    String userCode = dataJson.getString("userCode");
    addUser(userCode);
    sendOnlineMessage();
    }
    });

    socketServer.start();
    }catch(Exception e) {
    ServiceLog.error("启动在线统计用户服务失败: " + e.getMessage(), e);
    }
    }

    private static void addUser(String userCode) {
    if(StringUtil.isEmpty(userCode)) {
    return;
    }
    if(!userSet.contains(userCode)) {
    userSet.add(userCode);
    }
    }

    private static void removeUser(String userCode, SocketIOClient client) {

    if(StringUtil.isEmpty(userCode)) {
    return;
    }
    userSet.clear();
    Collection<SocketIOClient> clients = socketServer.getAllClients();
    for (SocketIOClient c : clients) {
    if(c.getSessionId().equals(client.getSessionId())) {
    continue;
    }
    HandshakeData handshakeData = c.getHandshakeData();
    String uCode = handshakeData.getSingleUrlParam("userCode");
    userSet.add(uCode);
    }
    }

    private static void sendOnlineMessage() {
    Collection<SocketIOClient> clients = socketServer.getAllClients();
    //result.put("CLIENT_NUM", clientCount.get());
    result.put("ONLINE_NUM", userSet.size());
    for (SocketIOClient c : clients) {
    c.sendEvent("HEARTBEAT_EVENT", result);
    }
    }

    public static void stopSocketIOServer(){
    if(socketServer != null){
    socketServer.stop();
    socketServer = null;
    }
    }
    }
    只需要在ServletContextListener初始化时调用:

    OnlineUserCounter.startSocketIOServer();
    ;销毁时调用:

    OnlineUserCounter.stopSocketIOServer();
    2.前端js示例代码:

    var socket = io.connect('http://172.28.50.113:9093?userCode=admin');

    socket.on('connect', function() {
    console.log('连接成功,可以处理初始化工作');
    });

    socket.on('HEARTBEAT_EVENT', function(data) {
    //监听HEARTBEAT_EVENT事件,只要用户数量有变化,即能及时收到推送消息
    console.log("后台推送消息:"+data);
    });
    后记:利用socketio,不仅可以统计用户量,还可以记录所有客户端的连接列表,或者登录用户列表信息。包括用户的IP、登录名等任何希望记录的业务信息。

  • 相关阅读:
    需要返回对象时候,不要以引用形式返回
    成对使用new和delete,传值传引用
    赋值重载的约定(1)
    oracle操作字符串:拼接、替换、截取、查找
    Oracle CASE WHEN 用法介绍
    oracle中如何对字符串进行去除空格的方法
    日期显示
    Oracle Cursor用法总结
    每天一个linux命令(26):用SecureCRT来上传和下载文件
    每天一个linux命令(25):linux文件属性详解
  • 原文地址:https://www.cnblogs.com/java-llp/p/10892907.html
Copyright © 2011-2022 走看看