express redis socket 消息提醒方案:本地emit 輪循服務器獲取redis 再推送

在做項目時,需要實現消息提醒,因爲現在有多個項目,都需要實現。

爲了實現多項目公用,和以後項目也可以使用。

單獨開了個項目,起了個node 服務來實現消息提醒。

用express redis socket.io來實現的。

session 都存在redis裏,所有的服務都一樣。這樣實現了,sessio共享

只要其他項目登錄了,消息服務也就登錄了。

因爲要多個項目共用,所以會在項目中引用socket.io js 然後創建

var socket=io('http://localhost:8007');

鏈接到8007也就是消息服務器。

消息服務io connection 鏈接上後,通過socket.request.headers.sookie 來獲取請求的cookie 找到connect.sid 得到sid。

再從redis上查找對應的用戶信息。保存到鏈接socket上。然後發送emit open ,表示鏈接成功。

本地接收到後輪循向服務器發請message 請求來獲取消息。

服務器查詢redis獲取消息,並emit 返回。


以下是服務端代碼:

/*star 2016-8-20
socket 從請求中獲取cookie 也就是token 再從redis裏取到token對應的user 信息。
這後向socket頁面emit(open) 表示當前登錄用戶鏈接socket成功。
本地輪循發起emit message 事件,獲取用戶的提示條數。
服務器根據 userid 從redis裏讀取提示條數並返回。
----此爲node socket 消息服務器第一種解決方案
*/
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
var http = require('http');

var redis_api=require('./redis_api.js')


var port=8007;
var app = express();



// view engine setup
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// 設置 Session
app.use(session({
  store: new RedisStore({
    host: "127.0.0.1",
    port: 6379,
    db: 0
    //pass: 'yu'
  }),
  resave:false,
  saveUninitialized:false,
  secret: 'keyboard cat'
}))

app.use(function(req,res,next){
  console.log(req.url);
  next();
})




app.get('/socket',function(req,res){
	res.header("Access-Control-Allow-Origin", "*");
	//console.log(req.session.username)
	res.send(req.session)
})


var server = http.createServer(app);

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);


var io=require('socket.io')(server);
var users=[]
io.on('connection',function(socket){	
	console.log('open')
	//獲取請求cookie
	var cookie_string=decodeURIComponent(socket.request.headers.cookie)
	//正則匹配 獲取sid
	var s=/connect.sid=([^\.]+)/g.exec(cookie_string);
	var sid='';
	if(s && s.length>1){
		sid=s[1].split(':')[1];
		//console.log(sid);
		var user;
		redis_api.getsid(sid,function(err,res){
			if(!err){
				user=res;			
				socket.emit('open',{sid:sid,user:user.user})
				socket.sid=sid;
				socket.user=user.user;
				//鏈接數測試
				/*var n=9000000;
				while(n--){
					users.push(socket);
				}*/
			}
		})
	}
	socket.on('message',function(res){
		console.log(res);
		switch(res.action){
			case "read":
				read();
				break;
		}
	})
	function read(){
		redis_api.getmessage(socket.user.id,function(err,reply){
			if(!err){
				socket.emit('message',{type:1,action:'message',data:reply,number:users.length})
			}
		})
	}
	socket.on('disconnect',function(){
		console.log('close')
	})
	
})

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
    
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {

 console.log('localhost:'+port)
}
以下是redis_api代碼

var redis   = require('redis');
var client  = redis.createClient('6379', '127.0.0.1');


exports.getsid=function(sid,call){
	//client.select('0',function(err){			
			//if(!err){
				//console.log('select 0',err)
				client.get('sess:'+sid ,function(err,reply){
					console.log('------sess:'+sid)
					console.log('sess:',sid,err,reply)
					console.log('end ------sess:'+sid)
					if(err){
						call(err)
					}else{
						//console.log('sess:'+sid+'=',reply)
						call(0,JSON.parse(reply))
					}					
				})
			//}
	//})

}
//根據userid 獲取消息數
exports.getmessage=function(userid,call){
	client.select('0',function(err){
		if(!err){
			client.get('message:'+userid,function(err,reply){
				if(!err){
					console.log('message:'+userid+'='+reply)
					call(0,JSON.parse(reply))
				}
				// 關閉鏈接
           		//client.quit();
			})
		}
	})
}



以下是頁面代碼:

var socket=io('http://localhost:8007');
			socket.on('open',function(res){
				console.log('開了',res)
				time();
				//socket.emit('message',{id:1,type:1,action:'read'})
			})
			socket.on('message',function(res){
				console.log(res,new Date());
			})

			
			//以下爲輪循發請emit 獲取消息數
			function time(){
				setInterval(function(){
					socket.emit('message',{type:1,action:'read'})
					//socket.emit('message',{type:1,action:'read'})
				},3000)
			}

當然這種實現是有問題 的,並不是時時消息提醒。

而且當鏈接數大時不斷輪循會給服務器和帶寬帶來很大壓力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章