【博客大賽】100行js代碼實現網站在線用戶數量統計 nodejs + socket.io方案

需求提出

公司的在線培訓平臺,須要增長一個新功能:實時統計當前在線的用戶數量並在終端界面上顯示,須要的時候能夠查詢當前在線的用戶的明細。
有3種技術方案能夠選用:
1)改動後臺代碼,在用戶登陸和退出時將用戶在線信息記錄到數據庫中,經過查詢數據庫查詢用戶明細。這種方案稍微重了點,要改動原來後臺的代碼,這個功能的加入須要從新進行後臺代碼的更新和測試。總以爲不妥,實時性和準確性也難以保障。
2)使用消息隊列(message queue),將用戶登陸和退出的消息實時分發給一個獨立的記錄器模塊,由記錄器進行在線用戶的記錄和保存。這種方案依賴消息隊列消息傳遞的準確性和及時性。
3)採用socket.io技術,創建一個獨立的微服務,進行在線用戶的記錄。socket.io具備輕量、易維護的特色,客戶端具備自動重連機制,能夠保障數據的準確性和及時性。
權衡後決定採用第3種方案。javascript

技術方案

nodejs + socket.io
nodejs是後臺運行環境,使用socket.io模塊進行在線用戶的記錄和通訊。css

服務器端

代碼

  1. 主程序代碼 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);
           }
        }

    });
});

這個代碼很好理解:html

  • 客戶端與服務器創建鏈接後,首先發送一個"user"消息給服務器,彙報用戶信息。用戶信息能夠包括任何須要記錄的信息,如:用戶姓名、用戶編號、所在的分組或應用(room),當前訪問的頁面等。
  • 服務器收到用戶信息後記錄到內存中,而後將在線用戶總數發送給全部用戶。
  • 客戶端能夠隨時經過發送「get-users」請求消息查詢在線用戶列表。這個功能很酷,能夠看到在線用戶詳細列表。
  1. 依賴定義文件 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"
}

原文件拷貝到代碼目錄便可,後面使用。java

部署與運行

  1. 首先正確安裝nodejs,參見 https://blog.51cto.com/livestreaming/2314592
  2. 安裝依賴包
    在代碼根目錄(app.js和package.jso所在目錄)運行命令:
npm install
  1. 修改服務端口
    在上述app.js代碼中,修改web服務端口,默認是86,確保各級防火牆開放該端口:node

    var port    = 86;
  2. 運行程序
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)提交用戶信息時把暱稱、頭像等信息提交進來,顯示用戶列表時能夠更酷
個人一個在線用戶效果:
【博客大賽】100行js代碼實現網站在線用戶數量統計 nodejs + socket.io方案web

相關文章
相關標籤/搜索