重复造轮子之基于nodejs的聊天室
2013-03-01 14:20
218 查看
首先说明下,这帖子虽然是原创,但是功能网上已经有很多实现的有很多。我只是记录下自己的进步而已
配置nodejs的环境大家可以看看我的另外一篇博文简单完成nodejs的服务创建。
好了,我们先从服务端代码开始,基于nodejs哦。
简单的config.js文件,代码中的解释如果看不懂,可以再次阅读简单完成nodejs的服务创建这篇博文。如果还是不明白,可以留言询问。
然后我们看看消息推送的代码
接下来,我们看下客户端的脚本,需要说明的是因为刚开始写的时候需求不同,个别命名还是初期的命名,从英文角度看,有点变扭。
好了,山寨的聊天室第一个版本就写到这了,想交流的同学,可以加我的群43881427,验证码:小菜+我
也可以直接留言,有更优的解决方案,最好还是留言吧。大家一起看看
配置nodejs的环境大家可以看看我的另外一篇博文简单完成nodejs的服务创建。
好了,我们先从服务端代码开始,基于nodejs哦。
简单的config.js文件,代码中的解释如果看不懂,可以再次阅读简单完成nodejs的服务创建这篇博文。如果还是不明白,可以留言询问。
var express = require('express') , routesConfig = require('./routes/config') , http = require('http') , routes = require('./routes/config') ; var app = express(), //端口号 port = 8888; app.configure(function () { //定义一个私有变量减少作用域链的检索消耗(其实没必要这么写,1亿次检索才会有性能差异) var _app = app, _express = express //设置视图文件 _app.set('views', __dirname + '/views'); //设置模板引擎 _app.set('view engine', 'ejs'); //静态资源管理 _app.use(express.static(__dirname + '/')); app.use(express.favicon()); //(这个自动处理是将post携带的数据,放到request.body里面) _app.use(_express.bodyParser()); //使用请求头数据自动处理: //(这个自动处理是将,某些不是请求头数据在head中或者直接携带在postData中的请求头信息写入到request.method,如果信息在postData里面,会将post.body里面的请求头信息删除) _app.use(_express.methodOverride()); //使用调试? //这个不是很清楚看接口对应代码貌似和debug有关 _app.use(_app.router); }); app.get('/', routesConfig.default); //接受消息 var chat = require("./routes/chat_box/push"); app.get('/push', chat.push); //异常处理 app.configure('development', function () { app.use(express.errorHandler()); }); //创建这个服务,并指定端口,完了之后初始端口号 http.createServer(app).listen(port, function () { console.log("Express server listening on port " + port); });在这段代码中,默认访问比如:http://xxxx.xxxx.xxx/ 这种类型的自动执行了routesConfig.default,这个我就不细说了,反正就输出个html而已。
然后我们看看消息推送的代码
//url模块(nodejs) var urllib = require('url'); /*socket模块(nodejs) 开启推送端口端口号为:9999,这个端口号其实随意的,只要木有被占用就行 */ var io = require('socket.io').listen(9999); //简单队列 var queue = function () { var self = this; this.list = []; this.add = function (data, cb) { self.list.push(data); cb && cb(); }; this.get = function () { return self.list.shift(); }; }; //事实上这个user是个山寨的数据库(我用来缓存数据的,这里偷懒了) var user = {}; /* 事件绑定 connection事件为,服务端出现链接后执行 我在该事件中表现为,每存在一个链接用户,就为其开出一片内存,用于存放推送信息,这里我没优化,用户多的情况下 应该很坑爹 然后执行推送数据的监听 */ io.sockets.on('connection', function (socket) { (!user[socket.id]) && (user[socket.id] = new queue()); _push(socket); }); /* 开启推送数据的监听,用setInterval,伪造出多线程 这边我没什么好的想法,有好的解决方案,求交流 */ var _push = function (socket) { var _setInterval; _setInterval = setInterval(function () { var item = user[socket.id] && user[socket.id].get(); if (item) { socket.emit("chat_box", item); } }, 100); }; /* 接受发送消息的接口,记得那个配置的js吗? var chat = require("./routes/chat_box/push"); app.get('/push', chat.push); 这句话就是转到这个接口来处理了 */ exports.push = function (req, res) { var params , uname , quantity , text; params = urllib.parse(req.url, true).query; uname = params.uname; quantity = params.quantity; text = params.text; //接受到发送消息后,为每个链接用户加入推送消息 for (var i in user) { user[i].add({ userName: uname, flowersQuantity: quantity, text: text }) } //服务端的监控,可以在命令提示符中看到 console.log('有新消息'); };好了服务端的代码就这些了,这里主要还是依靠socket.io这个nodejs插件。
接下来,我们看下客户端的脚本,需要说明的是因为刚开始写的时候需求不同,个别命名还是初期的命名,从英文角度看,有点变扭。
//简单队列 var queue = function () { var self = this; this.list = []; this.add = function (data, cb) { self.list.push(data); cb && cb(); }; this.get = function () { return self.list.shift(); }; } //接收队列 var flowersQueue = new queue() //单例队列 , singletonMsgQueue = new queue() //包队列 , boxMsgQueue = new queue() //用户送花总数存住对象 , userData = {} , $chat_box = $("#chat_box") ; /* 实现逻辑: 1、出现新数据 2、数据进入接收队列 3、执行进接收队列的回调(判断送花数据是单例还是包,我把包定义成需要刷屏的数据) 4、单例数据,就是不需要刷屏的数据,直接进入单例队列 5、包数据,拆分成单例数据进入单例队列 6、使用监听器监听单例队列,按照步长输出 */ //添加新的送花数据进队列后的回调(内部判断,单例送花,还是送花包) var flowersQueueAddCallBack = function () { //从队列获取一个数据 var _item = flowersQueue.get(); //不存在就返回。。。你懂得 if (!_item) return; //如果数据中的某个属性值确定是需要刷屏处理的,我这边是因为我定的业务逻辑所以这么写了 if (_item.flowersQuantity == 20) { //进入包队列,并执行回调 boxMsgQueue.add(_item, function () { boxMsgQueueAddCallBack(); }); } else { /* 这边也有业务逻辑,就是发普通聊天信息和送花信息,这些不纠结,这边就是直接进入单例队列 事实上我这边这么处理会因为网速,机器好坏,导致聊天,和刷屏一起的时候 没法所有用户同步。 这边其实可以,直接对容器append,单例数据直接获取到,直接插入,我这边暂时没这么修改,下个版本我考虑把它优化掉 */ if (_item.flowersQuantity != 0) { userData[_item.userName] = (userData[_item.userName] || 0) + (_item.flowersQuantity - 0); singletonMsgQueue.add('<p>' + _item.userName + '赠送' + _item.flowersQuantity + '朵鲜花,共' + userData[_item.userName] + '朵</p>'); } else { singletonMsgQueue.add('<p>' + _item.userName + ":" + _item.text + '</p>'); } } }; //添加新的包数据进,包数据队列后的回调(出现新的包数据,根据步长,拆分成单例数据进入单例队列) var boxMsgQueueAddCallBack = function () { //取值,同上面的方法 var _item = boxMsgQueue.get(); var i, _setInterval; if (!_item) return //按照步长插入单例队列 i = 0; _setInterval = setInterval(function () { i++; userData[_item.userName] = (userData[_item.userName] || 0) + 1; singletonMsgQueue.add('<p>' + _item.userName + '赠送一朵鲜花,共' + userData[_item.userName] + '朵</p>'); if (i == _item.flowersQuantity) { clearInterval(_setInterval); } }, 200); }; //监听单例队列,插入文字(不管是单例数据还是包数据,经过处理都进入单例队列) var monitorSingletonMsgQueue = function () { //获取队列中的第一个 var _item = singletonMsgQueue.get(); var i; //队列存在数据 if (_item) { //插入一条新数据 $chat_box.append(_item).scrollTop(10000); ($chat_box.find("p").length > 200) && ($chat_box.find("p:eq(0)").remove()); //队列数据过多,则加快显示速度 if (singletonMsgQueue.list.length > 100) { i = singletonMsgQueue.list.length; while (i--) { $chat_box.append(singletonMsgQueue.get()).scrollTop(10000); ($chat_box.find("p").length > 200) && ($chat_box.find("p:eq(0)").remove()); } } } } //监听器 setInterval(function () { monitorSingletonMsgQueue(); }, 200); //获取推送信息 var socket = io.connect('http://10.0.252.124:9999'); //这边就是获取推送信息的递归了,只要把推送来的数据放到,队列里面就可以了 socket.on('chat_box', function (data) { flowersQueue.add(data, function () { flowersQueueAddCallBack(); }); });
好了,山寨的聊天室第一个版本就写到这了,想交流的同学,可以加我的群43881427,验证码:小菜+我
也可以直接留言,有更优的解决方案,最好还是留言吧。大家一起看看
相关文章推荐
- 基于nodejs与websocket的加密认证聊天室
- 利用socket.io实现多人聊天室(基于Nodejs)
- Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G
- 利用socket.io实现多人聊天室(基于Nodejs)
- 基于NodeJS的秘室聊天室
- nodejs 基于socket.io实现聊天室
- 开发基于NodeJS的秘室聊天室
- GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。
- 基于NodeJs的局域网聊天室
- 基于Nodejs利用socket.io实现多人聊天室
- 实现一个无刷新的基于ajax的简易聊天室
- Netty 系列八(基于 WebSocket 的简单聊天室).
- 使用 AngularJS & NodeJS 实现基于 token 的认证应用
- Golang代码搜集-基于websocket+vue.js的简易聊天室
- 6.8: 基于jQuery的Ajax聊天室程序
- 基于Nodejs生态圈的TypeScript+React开发入门教程
- 开发基于UDP广播的小型局域网聊天室
- 基于nodejs+zookeeper服务发现
- 基于Struts2和hibernate的WebSocket聊天室的实现教程六:界面原型及通信请求
- Android基于XMPP Smack openfire 开发的聊天室