最近作了一个实时游戏,后端nodejs+mongodb+redis socket.io;socket.io是nodejs的websocket的最好的后端插件了,基本上社区都在用都在讨论;四万多颗星了,https://github.com/socketio/socket.io 。我的理解因为它良好的兼容性易用性完全是websocket的集大成者;本身是在nodejs里发源的,但也有不少语言版本;socket.io先扯到这,本文的设定是你已经对websocket/socket.io有较多的认识,写过相关应用,但仍觉得有必要提升,需要有效率的开发这方面的应用;
我们为什么要用redis,因为他比谁都快,他是key/value结构,他代替memcached,它是现在高并发服务端缓存应用的主流;
我在常规在服务端用的redis的姿势;
var reddb = redis.createClient(6379,'localhost');
reddb.set(openId,JSON.stringify(_session),callback);
。。。。
reddb.get(openId,(err,rs)=>JSON.parse(rs));
我们把一堆不知什么东西打包成字符串,然后准备好一个较长的以后看起来好唯一识别的键存到redis里。这看起来没什么,但set和get是初级应用。其实我很长一段时间就是用这种方式去工作。但我在一次做游戏的时候,有些无法忍受这样了。当我存的数据结构变化不大是无所谓。后来存的是交互强的东西存的_session里必须要有个数组,时时刻刻要推东西进去,又要删东西,数组主要可以让我过滤一下什么的,这样我就在想为什么redis没有一个数组让我用用呢。。。我找了一个还真有。
还好现在redis有了一个东西即smembers,这样你只用一个键可以维护好整个游戏所有的用户的状态了。。。因为我在后台实时会将登录的用户记录状态,
他在游戏中状态又要有变化,而我还要时时把一批用户拿出来和某一个新用户配对,这样我就可以工作了;smembers整个列表,srem删除其中一个,sadd增加一个;以下基本逻辑是你要修改一个先将他找出来删了然后再把改好的加进去。
var findMyData = async(uid,sid)=>{
//var uid = client.obj.userid;
var rs = await new Promise((resolve) => {
reddb().smembers('pvponline',(err,rs)=>{
if(err){
resolve(err);
}else{
//console.log('findMyData:',uid,rs)
var obj = uid?rs.find(i=>JSON.parse(i).userid == uid):
sid?rs.find(i=>JSON.parse(i).sid == sid):null;
if(obj){
resolve(JSON.parse(obj));
}else{
resolve();
}
}
})
})
return rs;
}
var setMyData = async(uid,obj)=>{
//var uid = client.obj.userid;
//var _key = 'pvp_'+uid;
var pvp = await findMyData(uid);
if(!pvp){
pvp = new Pvp();
pvp['userid'] = uid;
}else{
await new Promise((resolve) => {
reddb().srem('pvponline',JSON.stringify(pvp),(err,rs)=>{
resolve(rs)
})
})
}
for(var i in obj){
pvp[i] = obj[i];
}
var rs = await new Promise((resolve) => {
reddb().sadd('pvponline',JSON.stringify(pvp),(err,rs)=>{
resolve(rs)
})
})
return rs
}
var findOtherDataPvp = async(uid)=>{
//var uid = client.obj.userid;
var rs = await new Promise((resolve) => {
reddb().smembers('pvponline',(err,rs)=>{
if(err){
resolve(err);
}else{
//console.log('find other data:',rs)
var list = rs.filter(i=>
JSON.parse(i).userid != uid &&
JSON.parse(i).state==(10||11) &&
!JSON.parse(i).other
);
var obj = list[Math.floor(Math.random()*list.length)];
if(obj){
resolve(JSON.parse(obj));
}else{
resolve();
}
}
})
})
return rs;
}
在findOtherDataPvp里我能很好的对现在的用户状态进行识别和过滤。
这里要注意的坑点是smembers里的东西在修改之前需要删除,在推新东西也需要先将里面的元素找出来一个个的删除,不然会遇到无法识别undenfind;