使用Node.js+Socket.IO搭建WebSocket 实现多人群聊
来源:互联网 发布:淘宝750海报图片 编辑:程序博客网 时间:2024/05/17 07:14
今天我们做的就是无刷新实时多人聊天,最终效果我们可以看下:
Node.js
Node.js采用C++语言编写而成,它不是Javascript应用,而是一个Javascript的运行环境,据Node.js创始人Ryan Dahl回忆,他最初希望采用Ruby来写Node.js,但是后来发现Ruby虚拟机的性能不能满足他的要求,后来他尝试采用V8引擎,所以选择了C++语言。
Node.js支持的系统包括*nux、Windows,这意味着程序员可以编写系统级或者服务器端的Javascript代码,交给Node.js来解释执行。Node.js的Web开发框架Express,可以帮助程序员快速建立web站点,从2009年诞生至今,Node.js的成长的速度有目共睹,其发展前景获得了技术社区的充分肯定。
Socket.IO
Socket.IO是一个开源的WebSocket库,它通过Node.js实现WebSocket服务端,同时也提供客户端JS库。Socket.IO支持以事件为基础的实时双向通讯,它可以工作在任何平台、浏览器或移动设备。
Socket.IO支持4种协议:WebSocket、htmlfile、xhr-polling、jsonp-polling,它会自动根据浏览器选择适合的通讯方式,从而让开发者可以聚焦到功能的实现而不是平台的兼容性,同时Socket.IO具有不错的稳定性和性能。
编码实现:1.安装Node.js
根据自己的操作系统,去Node.js官网下载安装即可。我的是nginx:
yum install nodejsyum install npm
如果成功安装。在命令行输入node -v
和npm -v
应该能看到相应的版本号。node -v v0.10.26 npm -v 1.4.6
搭建WebSocket服务端
这个环节我们尽可能的考虑真实生产环境,把WebSocket后端服务搭建成一个线上可以用域名访问的服务,如果你是在本地开发环境,可以换成本地ip地址,或者使用一个虚拟域名指向本地ip。
进入到工作目录,如/usr/local/nginx/html,新建一个名为package.json的文件,内容
{ "name": "realtime-server", "version": "0.0.1", "description": "my first realtime server", "dependencies": {}}
接下来使用npm
命令安装express
和socket.io
12
npm install --save expressnpm install --save socket.io
安装成功后,应该可以看到工作目录下生成了一个名为node_modules
的文件夹,里面分别是express
和socket.io
,接下来可以开始编写服务端的代码了,新建一个文件:index.js
1234567891011
var app = require('express')();var http = require('http').Server(app);var io = require('socket.io')(http);app.get('/', function(req, res){res.send('<h1>Welcome Realtime Server</h1>');});http.listen(3000, function(){console.log('listening on *:3000');});
命令行运行node index.js
,如果一切顺利,你应该会看到返回的listening on *:3000
字样,这说明服务已经成功搭建了。此时浏览器中打开http://localhost:3000
应该可以看到正常的欢迎页面。
如果你想要让服务运行在线上服务器,并且可以通过域名访问的话,可以使用Nginx做代理,在nginx.conf中添加如下配置,然后将域名(比如:realtime.plhwin.com)解析到服务器IP即可。
12345678
server{ listen 80; server_name realtime.plhwin.com; location / { proxy_pass http://127.0.0.1:3000; }}
完成以上步骤,http://realtime.plhwin.com:3000
的后端服务就正常搭建了。
服务端代码实现
前面讲到的index.js
运行在服务端,之前的代码只是一个简单的WebServer欢迎内容,让我们把WebSocket服务端完整的实现代码加入进去,整个服务端就可以处理客户端的请求了。完整的index.js
代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
var app = require('express')();var http = require('http').Server(app);var io = require('socket.io')(http);app.get('/', function(req, res){res.send('<h1>Welcome Realtime Server</h1>');});//在线用户var onlineUsers = {};//当前在线人数var onlineCount = 0;io.on('connection', function(socket){console.log('a user connected');//监听新用户加入socket.on('login', function(obj){//将新加入用户的唯一标识当作socket的名称,后面退出的时候会用到socket.name = obj.userid;//检查在线列表,如果不在里面就加入if(!onlineUsers.hasOwnProperty(obj.userid)) {onlineUsers[obj.userid] = obj.username;//在线人数+1onlineCount++;}//向所有客户端广播用户加入io.emit('login', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});console.log(obj.username+'加入了聊天室');});//监听用户退出socket.on('disconnect', function(){//将退出的用户从在线列表中删除if(onlineUsers.hasOwnProperty(socket.name)) {//退出用户的信息var obj = {userid:socket.name, username:onlineUsers[socket.name]};//删除delete onlineUsers[socket.name];//在线人数-1onlineCount--;//向所有客户端广播用户退出io.emit('logout', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});console.log(obj.username+'退出了聊天室');}});//监听用户发布聊天内容socket.on('message', function(obj){//向所有客户端广播发布的消息io.emit('message', obj);console.log(obj.username+'说:'+obj.content);}); });http.listen(3000, function(){console.log('listening on *:3000');});
客户端代码实现
进入客户端工作目录/workspace/wwwroot/plhwin/demo.plhwin.com/chat
,新建一个index.html
:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <meta name="format-detection" content="telephone=no"/> <meta name="format-detection" content="email=no"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" name="viewport"> <title>多人聊天室</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <!--[if lt IE 8]><script src="./json3.min.js"></script><![endif]--> <script src="http://realtime.plhwin.com:3000/socket.io/socket.io.js"></script> </head> <body> <div id="loginbox"> <div style="width:260px;margin:200px auto;"> 请先输入你在聊天室的昵称 <br/> <br/> <input type="text" style="width:180px;" placeholder="请输入用户名" id="username" name="username" /><input type="button" style="width:50px;" value="提交" onclick="CHAT.usernameSubmit();"/> </div> </div> <div id="chatbox" style="display:none;"> <div style="background:#3d3d3d;height: 28px; width: 100%;font-size:12px;"> <div style="line-height: 28px;color:#fff;"> <span style="text-align:left;margin-left:10px;">Websocket多人聊天室</span> <span style="float:right; margin-right:10px;"><span id="showusername"></span> | <a href="javascript:;" onclick="CHAT.logout()" style="color:#fff;">退出</a></span> </div> </div> <div id="doc"> <div id="chat"> <div id="message" class="message"><div id="onlinecount" style="background:#EFEFF4; font-size:12px; margin-top:10px; margin-left:10px; color:#666;"></div> </div> <div class="input-box"> <div class="input"><input type="text" maxlength="140" placeholder="请输入聊天内容,按Ctrl提交" id="content" name="content"> </div> <div class="action"> <button type="button" id="mjr_send" onclick="CHAT.submit();">提交</button> </div> </div> </div> </div> </div> <script type="text/javascript" src="./client.js"></script> </body></html>
上面的html内容本身没有什么好说的,我们主要看看里面的4个文件请求:
1、realtime.plhwin.com:3000/socket.io/socket.io.js
2、style.css
3、json3.min.js
4、client.js
第1个JS是Socket.IO提供的客户端JS文件,在前面安装服务端的步骤中,当npm安装完socket.io并搭建起WebServer后,这个JS文件就可以正常访问了。
第2个style.css文件没什么好说的,就是样式文件而已。
第3个JS只在IE8以下版本的IE浏览器中加载,目的是让这些低版本的IE浏览器也能处理json,这是一个开源的JS,详见:http://bestiejs.github.io/json3/
第4个client.js
是完整的客户端的业务逻辑实现代码,它的内容如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
(function () {var d = document,w = window,p = parseInt,dd = d.documentElement,db = d.body,dc = d.compatMode == 'CSS1Compat',dx = dc ? dd: db,ec = encodeURIComponent;w.CHAT = {msgObj:d.getElementById("message"),screenheight:w.innerHeight ? w.innerHeight : dx.clientHeight,username:null,userid:null,socket:null,//让浏览器滚动条保持在最低部scrollToBottom:function(){w.scrollTo(0, this.msgObj.clientHeight);},//退出,本例只是一个简单的刷新logout:function(){//this.socket.disconnect();location.reload();},//提交聊天消息内容submit:function(){var content = d.getElementById("content").value;if(content != ''){var obj = {userid: this.userid,username: this.username,content: content};this.socket.emit('message', obj);d.getElementById("content").value = '';}return false;},genUid:function(){return new Date().getTime()+""+Math.floor(Math.random()*899+100);},//更新系统消息,本例中在用户加入、退出的时候调用updateSysMsg:function(o, action){//当前在线用户列表var onlineUsers = o.onlineUsers;//当前在线人数var onlineCount = o.onlineCount;//新加入用户的信息var user = o.user;//更新在线人数var userhtml = '';var separator = '';for(key in onlineUsers) { if(onlineUsers.hasOwnProperty(key)){userhtml += separator+onlineUsers[key];separator = '、';} }d.getElementById("onlinecount").innerHTML = '当前共有 '+onlineCount+' 人在线,在线列表:'+userhtml;//添加系统消息var html = '';html += '<div class="msg-system">';html += user.username;html += (action == 'login') ? ' 加入了聊天室' : ' 退出了聊天室';html += '</div>';var section = d.createElement('section');section.className = 'system J-mjrlinkWrap J-cutMsg';section.innerHTML = html;this.msgObj.appendChild(section);this.scrollToBottom();},//第一个界面用户提交用户名usernameSubmit:function(){var username = d.getElementById("username").value;if(username != ""){d.getElementById("username").value = '';d.getElementById("loginbox").style.display = 'none';d.getElementById("chatbox").style.display = 'block';this.init(username);}return false;},init:function(username){/*客户端根据时间和随机数生成uid,这样使得聊天室用户名称可以重复。实际项目中,如果是需要用户登录,那么直接采用用户的uid来做标识就可以*/this.userid = this.genUid();this.username = username;d.getElementById("showusername").innerHTML = this.username;this.msgObj.style.minHeight = (this.screenheight - db.clientHeight + this.msgObj.clientHeight) + "px";this.scrollToBottom();//连接websocket后端服务器this.socket = io.connect('ws://realtime.plhwin.com:3000');//告诉服务器端有用户登录this.socket.emit('login', {userid:this.userid, username:this.username});//监听新用户登录this.socket.on('login', function(o){CHAT.updateSysMsg(o, 'login');});//监听用户退出this.socket.on('logout', function(o){CHAT.updateSysMsg(o, 'logout');});//监听消息发送this.socket.on('message', function(obj){var isme = (obj.userid == CHAT.userid) ? true : false;var contentDiv = '<div>'+obj.content+'</div>';var usernameDiv = '<span>'+obj.username+'</span>';var section = d.createElement('section');if(isme){section.className = 'user';section.innerHTML = contentDiv + usernameDiv;} else {section.className = 'service';section.innerHTML = usernameDiv + contentDiv;}CHAT.msgObj.appendChild(section);CHAT.scrollToBottom();});}};//通过“回车”提交用户名d.getElementById("username").onkeydown = function(e) {e = e || event;if (e.keyCode === 13) {CHAT.usernameSubmit();}};//通过“回车”提交信息d.getElementById("content").onkeydown = function(e) {e = e || event;if (e.keyCode === 13) {CHAT.submit();}};})();
至此所有的编码开发工作全部完成了,在浏览器中打开demo.plhwin.com/chat/就可以看到效果了。上面所有的客户端和服务端的代码可以从Github上获得,点这里跳转到Github项目主页,或者在命令行将代码Clone到本地。
git clone https://github.com/plhwin/nodejs-socketio-chat.git
下载本地后有两个文件夹 client
和 server
,client
文件夹是客户端源码,可以放在Nginx/Apache的WebServer中,也可以放在Node.js的WebServer中。后面的server
文件夹里的代码是websocket服务端代码,放在Node.js环境中,使用npm安装完 express
和 socket.io
后,node index.js
启动后端服务就可以了。
- 使用Node.js+Socket.IO搭建WebSocket 实现多人群聊
- 使用Node.js+Socket.IO搭建WebSocket 实现多人群聊
- 使用Node.js+Socket.IO搭建WebSocket
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用socket.io和node.js搭建websocket应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用(聊天室)
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 10023---使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- 使用Node.js+Socket.IO搭建WebSocket实时应用
- TCP/IP详解--TCP首部选项中时间戳选项
- iOS 将一串 毫秒数 字符串 转换成 分 秒 毫秒 的格式*
- 常用正则表达式
- 艺术编程-技术之声第一期
- kafka入门
- 使用Node.js+Socket.IO搭建WebSocket 实现多人群聊
- 版本更新的弹窗显示功能
- SparkStandalone模式安装
- 大数据和空间限制问题专题(二)
- Fragment懒加载
- Android 之 Activity内控件与软键盘
- php 写sql,获取下一级的code
- php知识点滴
- 判断区间内的素数个数