Socket.io 學習筆記三

Socket.io 學習筆記三

前言

上次說到關於socket鏈接受權的問題,有好心人提示說到session-socket開源項目,能夠在創建鏈接後進行session相關操做,操做挺方便,很感謝這位朋友。個人目的是在握手階段,經過會話斷定權限,暨是否創建鏈接,因此只能本身查閱中間件代碼,而後COPY須要的。javascript

Connect Session

Connect相關的會話存儲我知道四種,cookie-based,memory-store,redis,mongodb.java

  • cookie-based方案數據直接存儲在cookie裏面,解析以後便可得到。node

  • memory-store方案,使用內存作容器,來存儲數據,因爲中間件使用了閉包特性,若是不對中間件動手腳的話,是沒法訪問這些數據,並且我是Express和socket.io分離的,更不可能拿到數據,因此此路不通。redis

  • connect-redis方案,將數據放入redis數據庫,這樣不一樣進程均可以獲取到session數據。Cookie解析以後獲取sessionId,經過sessionId從redis獲取數據。mongodb

  • mongodb方案,跟redis機理相同,再也不贅述。數據庫

Connect-redis

  • 啓用connect-redis session。
var express =require('express');
var app = express();
var RedisStore = require('connect-redis')(express);
app.use(express.cookieParser('love'));
app.use(express.session({key: 'lovestory', secret: 'lovestory',
    store: new RedisStore({ host: '127.0.0.1', port: 6379})
}));
  • socket.io部分
var io = require('socket.io').listen(1338);
var utils = require('connect/lib/utils.js');
var cookie = require('connect/node_modules/cookie-parser/node_modules/cookie');
var redis = require('redis');
var client = redis.createClient(6379,'127.0.0.1');
//鏈接受權斷定,相關參數須要跟啓用Session的參數相同
io.sockets.authorization(function (handshakeData, callback) {
    //cookie解析,獲取sessionId
    var cookies = handshakeData.headers.cookie;
    var secret = 'lovestory';
    var key  = 'lovestory';
    var prefix = 'sess:';
    var sessionId = null;
    if (cookies) {
        cookies = cookie.parse(cookies);
        cookies = utils.parseSignedCookies(cookies, secret);
        cookies = utils.parseJSONCookies(cookies);
        if(cookies[key]) {
            sessionId = cookies[key];
        }
      }
   //從redis獲取數據
    var sid = prefix + sessionId;
    client.get(sid,function(err,data){
        var result = JSON.parse(data);
        if (result.user){
            for (var i in handshakeData) {
                delete handshakeData[i];
            }
            handshakeData.user = result.user;
            callback(null,true);
        }else{
            callback(null,false);
        }
    });
});
//存儲user,socketId鍵值對,須要單點推送的時候經過user獲取對應的socketId便可。 
io.sockets.on('connection', function (socket) {
    client.set(socket.handshake.user,socket.id);
    io.sockets.socket(socket.id).send('Do you love this girl!!!');
});

Cookie-based更加簡單一些

  • Express部分
var express =require('express');
var app = express();
app.use(express.cookieParser('lovestory'));
app.use(express.cookieSession({key: 'lovestory', secret : 'lovestory'});
  • socket.io部分
var io = require('socket.io').listen(1338);
var utils = require('connect/lib/utils.js');
var cookie = require('connect/node_modules/cookie-parser/node_modules/cookie');
//鏈接受權斷定,相關參數須要跟啓用Session的參數相同
io.sockets.authorization(function (handshakeData, callback) {
    //cookie解析,獲取cookie中的session數據
    var cookies = handshakeData.headers.cookie;
    var secret = 'lovestory';
    var key  = 'lovestory';
    if (cookies) {
        cookies = cookie.parse(cookies);
        cookies = utils.parseSignedCookies(cookies, secret);
        cookies = utils.parseJSONCookies(cookies);
        if(cookies[key]) {
            session = JSON.parse(cookies[key]);
        }
      }
});

問題引伸

上述代碼比較原始,由於基本上是COPY出來的,不過能夠實現我最初的想法。可是新問題也冒出來了,我如何得知,何時,須要向哪些用戶,推送什麼消息。例如SNS,一位用戶更新了狀態,須要推送給他的朋友,就是須要主動向瀏覽器端推送消息的時候,如何通知到這個進程。。。。。。。express

粗略構想(「進程」只爲敘述方便,略有不妥)

  • Websocket握手階段是經過HTTP協議完成的,socket.io負責監聽upgrade,connection事件,能夠與普通HTTP server共存。經過HTTP模塊監聽普通http請求,當業務邏輯進程完成相應工做,斷定須要向其餘用戶推送消息時,向推送進程發出http請求,附帶需推送內容便可。json

  • 業務邏輯進程與推送進程創建socket鏈接,當業務邏輯進程完成相應工做,斷定須要向其餘用戶推送消息時,經過socket發送消息便可。瀏覽器

簡易實現

  • socket.io與普通HTTP服務同時存在
var http = require('http');
var app = http.createServer(function(req,res){});
var io = require('socket.io').listen(app);
app.listen(1338);
  • HTTP請求body部分目測須要包含如下信息。
    服務器

    字段 功能
    type 必需。single,room,或all,對應單點推送,羣組推送,全局推送
    pointer 必需。指明須要推送的目標,若typeall,顯式聲明true
    content 必需。指明須要推送的內容
  • 事件監聽函數(請原諒個人大嵌套~~|||)

function(req,res){
    jsonBody(req,res,function(err,data){
        if(err) {
            res.statusCode = 400;
            res.end('Bad request, json body only');
        }else{
           if (data.type && data.pointer && data.content) {
               switch (data.type) {
                   case 'all' :
                     io.sockets.send(data.content);
                     res.end('success');
                     break;
                   case 'room' :
                     io.sockets.in(data.pointer).send(data.content);
                     res.end('success');
                     break;
                   case 'single' :
                     client.get(data.pointer, function(err,result){
                         if(result) {
                             io.sockets.socket(result).send(data.content);
                             res.end('success');
                         }
                     })
                   default :
                     res.end('unexpected type');
                     break;
               }
           }else{
               res.end('Bad request!');
           }
        }
    })
}

代碼還欠缺不少打磨,不過基本功能已經出來了。

  • 關於服務器間socket鏈接,基本理念是相同的,就再也不往坑裏跳。

我的總結

到此爲止,socket.io常規使用已經所有over,涉及到的相關代碼私下繼續打磨。

相關文章
相關標籤/搜索