您的位置:首页 > 数据库 > Redis

express redis socket 消息提醒方案:本地emit 轮循服务器获取redis 再推送

2016-08-22 11:00 357 查看
在做项目时,需要实现消息提醒,因为现在有多个项目,都需要实现。

为了实现多项目公用,和以后项目也可以使用。

单独开了个项目,起了个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)
}

当然这种实现是有问题 的,并不是时时消息提醒。
而且当链接数大时不断轮循会给服务器和带宽带来很大压力。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: