公司的在線培訓平臺,須要增長一個新功能:實時統計當前在線的用戶數量並在終端界面上顯示,須要的時候能夠查詢當前在線的用戶的明細。
有3種技術方案能夠選用:
1)改動後臺代碼,在用戶登陸和退出時將用戶在線信息記錄到數據庫中,經過查詢數據庫查詢用戶明細。這種方案稍微重了點,要改動原來後臺的代碼,這個功能的加入須要從新進行後臺代碼的更新和測試。總以爲不妥,實時性和準確性也難以保障。
2)使用消息隊列(message queue),將用戶登陸和退出的消息實時分發給一個獨立的記錄器模塊,由記錄器進行在線用戶的記錄和保存。這種方案依賴消息隊列消息傳遞的準確性和及時性。
3)採用socket.io技術,創建一個獨立的微服務,進行在線用戶的記錄。socket.io具備輕量、易維護的特色,客戶端具備自動重連機制,能夠保障數據的準確性和及時性。
權衡後決定採用第3種方案。javascript
nodejs + socket.io
nodejs是後臺運行環境,使用socket.io模塊進行在線用戶的記錄和通訊。css
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); } } }); });
這個代碼很好理解:html
{ "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" }
原文件拷貝到代碼目錄便可,後面使用。java
npm install
修改服務端口
在上述app.js代碼中,修改web服務端口,默認是86,確保各級防火牆開放該端口:node
var port = 86;
node app.js
客戶端代碼就是網頁代碼啦,能夠根據須要提交用戶信息、顯示用戶數量和查詢用戶列表。
示例代碼:ios
<!DOCTYPE html> <html> <head> <meta http-equiv='Content-Type' content='text/html; charset=utf-8' /> <link href="bootstrap.min.css" rel="stylesheet" type="text/css" /> <title></title> </head> <body> <a href=""> <span class="glyphicon glyphicon-user" aria-hidden="true"></span> 在線用戶 <span class="badge badge-danger" style="background-color: red;" id="user-count">12</span> </a> </body> </html> <script src="socket.io.js"></script> <script type="text/javascript"> var io_host = "www.myhost.com"; //輸入正確的域名或IP,就是前面啓動服務的那臺機器的域名或IP var io_server = "http://" + io_host + ":86"; //注意端口 var socket = io(io_server); var room = location.host; /** *顯示用戶數量的代碼 */ function readerUserNumber(data){ console.log(data); var divuser = document.getElementById("user-count"); if(divuser) { divuser.innerHTML = data.user_num; } } socket.on('connect', function(){ console.log("connected to server..."); //提交用戶信息 var info = {}; info.url = location.href; info.username = "myname"; socket.emit("user",room,info,function(msg){ readerUserNumber(msg); }); //查詢用戶明細 socket.emit("get-users",function(data){ console.log("render by get-users..."); console.log(data); }); }); socket.on('disconnect', function(){ }); socket.on('online-number', function(data){ //用戶數量更新 console.log("online number:"); readerUserNumber(data); }); </script>
基於這個應用,還能夠實現以下效果:
1)將在線用戶數採樣記錄入庫,用於網站熱度分析和用戶訪問趨勢分析
2)將用戶訪問歷史記錄如庫,跟蹤用戶訪問軌跡
3)提交用戶信息時把暱稱、頭像等信息提交進來,顯示用戶列表時能夠更酷
個人一個在線用戶效果:
web