100行js代码实现网站在线用户数量统计 nodejs + socket.io方案
公司的在线培训平台,需要增加一个新功能:实时统计当前在线的用户数量并在终端界面上显示,需要的时候可以查询当前在线的用户的明细。
有3种技术方案可以选用:
1)改动后台代码,在用户登录和退出时将用户在线信息记录到数据库中,通过查询数据库查询用户明细。这种方案稍微重了点,要改动原来后台的代码,这个功能的加入需要重新进行后台代码的更新和测试。总觉得不妥,实时性和准确性也难以保障。
2)使用消息队列(message queue),将用户登录和退出的消息实时分发给一个独立的记录器模块,由记录器进行在线用户的记录和保存。这种方案依赖消息队列消息传递的准确性和及时性。
3)采用socket.io技术,建立一个独立的微服务,进行在线用户的记录。socket.io具有轻量、易维护的特点,客户端具有自动重连机制,可以保障数据的准确性和及时性。
权衡后决定采用第3种方案。
技术方案
nodejs + socket.io
nodejs是后台运行环境,使用socket.io模块进行在线用户的记录和通信。
服务器端
代码
主程序代码 app.js
复制
var express = require("express");
var app = express();
var http = require("http");
var server = http.createServer(app);
var io = require("socket.io");
var ios = io.listen(server);
var port = 86;
server.listen(port);
console.log("start server on port: " + port);
//辅助函数,根据room名称获取room对象
function ioRoom(name){
return ios.nsps["/"].adapter.rooms[name];
}
//socket.io handling
ios.on("connection", function(socket){
console.log("new client connected...");
socket.on("user", function(roomName,data, callback){
if(!data) data= {};
socket.join(roomName);
console.log("new user jioned " + roomName );
//保存用户数据
let room = ioRoom(roomName);
if(!room.users){
room.users = {};
}
socket.room = roomName;
var ip = socket.handshake.address;
if(socket.handshake.headers["x-forwarded-for"] != null){
ip = socket.handshake.headers["x-forwarded-for"];
}
data.socket_id = socket.id;
data.client_ip = ip;
data.addtime = (new Date()).getTime() / 1000;
room.users[socket.id] = data;
var count = Object.keys(room.users).length;
var backdata = {user_num:count,room:roomName};
if(typeof callback === "function"){
callback(backdata);
}
//发送用户数给所有人
ios.to(socket.room).emit("online-number", backdata);
});
//根据用户请求发送用户列表给客户端
socket.on("get-users", function(callback){
if(!socket.room){
console.log("user not jioned a room!");
return;
}
let room = ioRoom(socket.room);
callback(room.users);
});
// disconnect user handling
socket.on("disconnect", function () {
if(!socket.room){
return;
}
let room = ioRoom(socket.room);
if(room){
var users = room.users;
delete users[socket.id];
socket.leave(socket.room);
var count = Object.keys(users).length;
if(count>0){
var data = {user_num:count,room:socket.room};
ios.to(socket.room).emit("online-number", data);
}
}
});
});
这个代码很好理解:
客户端与服务器建立连接后,首先发送一个"user"消息给服务器,汇报用户信息。用户信息可以包括任何需要记录的信息,如:用户姓名、用户编号、所在的分组或应用(room),当前访问的页面等。
服务器收到用户信息后记录到内存中,然后将在线用户总数发送给所有用户。
客户端可以随时通过发送“get-users”请求消息查询在线用户列表。这个功能很酷,可以看到在线用户详细列表。
依赖定义文件 package.json
package.json定义这个nodejs程序运行所依赖的组件,有个这个文件之后,可以通过npm命令来安装依赖包。
代码:
复制
{
"name": "userCounter",
"version": "1.0.0",
"description": "a user counter nodejs app",
"keywords": [
"NodeJS",
"OnlineUserCounter",
],
"author": "www.ruiboyun.com",
"homepage": "http://www.ruiboyun.com/",
"private": "false",
"bundleDependencies": [
"passport.socketio"
],
"dependencies": {
"express": "3.2.*",
"socket.io": "^1.3.5",
"util": "^0.10.3"
},
"license": "MIT"
}
原文件拷贝到代码目录即可,后面使用。
部署与运行
首先正确安装nodejs,参见 https://blog.51cto.com/livestreaming/2314592
安装依赖包
在代码根目录(app.js和package.jso所在目录)运行命令:
复制
npm install
修改服务端口
在上述app.js代码中,修改web服务端口,默认是86,确保各级防火墙开放该端口:
复制
var port = 86;
运行程序
复制
node app.js
客户端
客户端代码就是网页代码啦,可以根据需要提交用户信息、显示用户数量和查询用户列表。
示例代码:
复制
在线用户
12
效果提升
基于这个应用,还可以实现如下效果:
1)将在线用户数采样记录入库,用于网站热度分析和用户访问趋势分析
2)将用户访问历史记录如库,跟踪用户访问轨迹
北海房价 http://bh.goufang.com/
3)提交用户信息时把昵称、头像等信息提交进来,显示用户列表时可以更酷
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341