博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用socketio做web系统在线用户量统计,和消息提醒
阅读量:5232 次
发布时间:2019-06-14

本文共 4215 字,大约阅读时间需要 14 分钟。

一开始想用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、登录名等任何希望记录的业务信息。

转载于:https://www.cnblogs.com/java-llp/p/10892907.html

你可能感兴趣的文章
HDU1272--小希的迷宫
查看>>
Event对象的事件句柄
查看>>
POJ 2367 Genealogical tree
查看>>
boost::asio async_write也不能保证一次发完所有数据 一
查看>>
CPython对象模型:Dict
查看>>
从客户端检测到有潜在危险的Request.Form值
查看>>
Bootstrap3 Grid system原理及应用
查看>>
angular项目中使用Primeng
查看>>
Redis教程(十四):内存优化介绍
查看>>
mysql performance schema的即时诊断工具-邱伟胜
查看>>
MYSQL 官方MYSQL源码文档介绍
查看>>
Log日志系统
查看>>
Azure 负载平衡器新分发模式
查看>>
Qt之可重入与线程安全
查看>>
Azure SQL 数据库弹性池现已面市
查看>>
基于visual Studio2013解决面试题之1105字符串压缩
查看>>
LaTeX技巧007:每一章开始的header引用名言应该怎么做?
查看>>
[LeetCode] Find Bottom Left Tree Value
查看>>
[Algorithm] Bloom Filter
查看>>
[LeetCode] Lexicographical Numbers
查看>>