1. 程式人生 > >用node.js(socket.io)實現資料實時推送

用node.js(socket.io)實現資料實時推送

1.setInterval每隔n秒去非同步拉取資料(缺點:更新不夠實時)

2. AJAX輪詢方式方式推送資料(缺點:服務端需要在死迴圈中反覆查詢資料庫)

3.websocket推送資料(缺點:僅支援html5標準的瀏覽器)

socket.io的簡要介紹

所有客戶端都通過socket.io掛在nodejs伺服器上(注意: 只是掛著,不需要任何迴圈,因為它是事件驅動的);需要推送訊息了,伺服器就與nodejs通訊(比如訪問某個地址來實現),告訴它推送什麼訊息到哪裡;nodejs收到推送訊號後,則通過socket.io實時傳輸資料給瀏覽器。這個其實也是一條單向的路,因為nodejs伺服器不具備與php通訊的能力,實際上也不需要,網頁上直接連php就可以了。

接下來開始整理下思路

1.正如簡要介紹中所說的首先要將客戶端都通過socket.io掛在nodejs伺服器上.

在使用者進入拍賣頁面後開始連線socket.io ,然後將當前客戶端的'使用者id','拍賣id','當前最高價','socket.id'儲存至node.js全域性變數socketUser中.

//客戶端

var socket = io.connect("http://demo.xiaocai.name":339");

socket.on('conn', function (data) {

  var postdata = {

'c_id'   : PageValue.charinfo.c_id,     //使用者id

        'c_name' : PageValue.charinfo.c_name,   //使用者暱稱

        'guid'   : PageValue.infodata.id,//拍賣id

        'price'  : PageValue.infodata.max_price,//當前最高價

  }

  socket.emit('login', postdata,function(result){

     console.log('登陸成功');

  });

});

//服務端

var   sio     = require('socket.io');

var   express = require('express');

var   app  =  module.export = express.createServer();

//初始化

var socketUser = {};

io  = sio.listen(app);

io.set('log level', 1);//將socket.io中的debug資訊關閉

//監聽連線

io.sockets.on('connection', function (socket){

    //響應連線

    io.sockets.emit('conn', { text: 'socketId:'+socket.id});

    //監聽使用者登入並存儲socket

    socket.on('login', function (data,fn) {

socketUser[socket.id] = {'c_id':data.c_id,'guid':data.guid,'price':data.price,'socket':socket};

    });

   //監聽斷線

    socket.on('disconnect', function(){

        console.log('-連結斷開['+socket.id+']-');

        delete socketUser[socket.id];

    });

});

2.需要推送訊息時伺服器就與nodejs通訊告訴它推送什麼訊息到哪裡

當有使用者出價時最高價格將發生改變,這時候通過socket.io來監聽這個動作,接著向掛在nodejs伺服器上的socket客戶端推送資料.

前端js:某個客戶端使用者給出了新的價格時發出請求‘postprice’並帶上當前拍賣的id

socket.emit('postprice', {'guid':PageValue.infodata.id});

服務端nodejs:服務端監聽請求postprice並執行pushprice方法向其它客戶端推送訊息

socket.on('postprice', function (data,fn) {

    console.log('-使用者出價['+data.guid+']-');

    pushprice(data.guid);

});

從redis快取中讀取出當前拍賣的最高價,然後遍歷該拍賣下的socketUser集合,若它的價格低於取出的最高價則向它推送最新的價格(並且更新它的最高價).GetRedisKey是個讀取reids的方法該方法在底部貼出.

    var pushprice = function(guid){

        console.log('-推送資料['+guid+']-');

        common_func.GetRedisKey("AuctionMaxPrice-"+guid,function(val){

            if(!val){

                return false;

            }

            for(var values in socketUser){

                if(  parseFloat(socketUser[values].price) < val && socketUser[values].guid == guid ){

                    socketUser[values].socket.emit('receive',{'nowprice':val});

                    socketUser[values].price = val;

                }

            }

        });

    }

3.客戶端接受推送的資料

socket.on('receive',function(maxprice){

    $('#NowUserTxt').html('¥'+maxprice);

});

GetRedisKey是公共函式中獲得redis快取的方法,這邊單獨貼出來

exports.GetRedisKey = function(key,fun){

    if( typeof redis_client == 'undefined' ){

        var redis      = require("redis");

        redis_client   = redis.createClient(RedisPort,RedisHost);

        redis_client.on("error", function (err) {

            common_func.insertlog("Error(redis): " + err);

        })

    }

    redis_client.get(key, function (err, reply) {

        if(reply){

            fun(reply.toString());

        }else{

            fun(false);

            common_func.insertlog('Error(redis): get('+key+') not data');

        }

    });

}