将js进行到底:node学习7
2018-02-24 12:33
295 查看
Node.js之Websocket技术
我第一次听说websocket之时,HTML5标准尚未公布,当时只有少数前瞻性浏览器携带了这个API。我对websocket最大的印象是,他可以解决我对“在线聊天系统”开发的疑惑(我一直想不通http如何保持长连接),这样我们无需使用轮询ajax和php无限循环去模拟,还记得2014年初那会我写了一个在线聊天室,那时候我真的应该用websocket技术的,php无限轮询的方式,只要3-4个人在线就可以让linux+apache服务器崩溃。
很可惜,我没有在php上使用过Websocket API,今天是我第一次将这个技术用来实践,使用node.js实现
引入模块
package.json{ "name":"chat-websocket", "version":"0.0.1", "description":"use websocket to create a char server", "dependencies":{ "express":"latest", "express-ws":"latest" } }
在引入http必备的express框架后,再引入基于express的中间件——express-ws
express-ws是express上的websocket中间件,为express提供了websocket请求处理功能
另外注意:《了不起的node.js》一书中使用的是websocket.io模块,两个东西原理,方法都差不多,我个人觉得io那个老了点,我选择了express-ws模块!主要是因为其与express配合效果更佳,专门为express而设计的中间件,何乐而不用呢?
做个测试
先来看看,node中使用express-ws的基本套路:index.js
var express = require("express"); //创建express下的http服务 var app = express(); //关联express-ws中间件 var expressWs = require("express-ws")(app); //express托管静态文件 app.use(express.static(__dirname+'/views',{'index':'index.html'})); app.ws('/ws',function(ws,req){ ws.on('message',function(msg){ console.log(msg); }) });; app.listen(80);
这个index.js是服务端代码
解析:
先引入express模块,并使用express()方法获得app对象
引入express-ws并构造对象,构造函数传入的是app对象,意思大概是绑定到express服务器上
通常接受http请求使用的是app.use(),而websocket请求则使用app.ws(),该方法就是中间件扩展的
message事件监听客户端发送的数据,并打印到终端上
views/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试</title> </head> <body> <input type="text" value="" id="msg"> <button id="submit">提交</button> </body> <script> window.onload=function(){ var ws = new WebSocket('ws://localhost/ws') var sub = document.getElementById("submit"); var msg = document.getElementById("msg") sub.addEventListener("click",function(){ ws.send(msg.value); }); ws.addEventListener("open",function(){ alert("WebSocket has been opened!"); }) } </script> </html>
这些为前端代码:实现了一个简单输入框,输入后主动通过websocket发送给服务端,服务端那边会打印再console中
效果:
测试成功,每一次点击提交都会显示!
WebSocket开发在线聊天室
功能点用户进入输入用户名可开始聊天
登入后提示当前在线用户
聊天内容会广播给聊天室其他在线用户
用户进入后提示xxx用户进入聊天室
用户关闭后提示xxx用户退出聊天室
package.json同上不变,具体设计逻辑参考另一篇博客,我用TCP API实现的聊天室程序http://www.cnblogs.com/devilyouwei/p/8423961.html
前端:index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试</title> <style> #inchat{ display:none; } ul{ list-style-type:none; } </style> </head> <body> <div id="inputname"> <input type="text" value="" id="msg" placeholder="输入一个聊天昵称"> <button id="submit">提交</button> </div> <div id="inchat"> <ul id="chat-content"> </ul> <textarea id="sendContent" value=""> </textarea> <button id="send">发送</button> </div> </body> <script> window.onload=function(){ var ws = new WebSocket('ws://localhost/ws');//需要修改为相应地址 var sub = document.getElementById("submit"); var msg = document.getElementById("msg") var ul = document.getElementById("chat-content"); var send = document.getElementById("send"); var sendContent = document.getElementById("sendContent"); sendContent.value=""; sub.addEventListener("click",function(){ ws.send(msg.value); }); send.addEventListener("click",function(){ ws.send(sendContent.value); sendContent.value="" }); ws.addEventListener("open",function(){ alert("WebSocket has been opened!"); }) ws.addEventListener("message",function(e){ var res = JSON.parse(e.data); //如果正在聊天中 if(res.ischat){ var li = document.createElement("li"); li.innerText = res.info; ul.appendChild(li); }else{ if(res.status == 1){ document.getElementById("inputname").style.display="none"; document.getElementById("inchat").style.display="block"; }else{ alert(res.info); } } }); } </script> </html>
注意:放到公网访问需要把localhost改成ip或者网址!
后端:index.js
var express = require("express"); //创建express下的http服务 var app = express(); //关联express-ws中间件 var expressWs = require("express-ws")(app); var users = {}; var count = 0; //express托管静态文件 app.use(express.static(__dirname+'/views',{'index':'index.html'})); //用ws方法而不是use方法 app.ws('/ws',function(ws,req){ var username = null; ws.on('message',function(msg){ if(!username){ if(users[msg]){ ws.send(JSON.stringify({status:0,info:"用户名重复请重试",ischat:false})); }else if(msg == ""){ ws.send(JSON.stringify({status:0,info:"用户名不能为空",ischat:false})); }else{ username = msg; count++; //用户+1 users[msg] = ws; ws.send(JSON.stringify({status:1,info:"注册成功,欢迎"+username,ischat:false})); console.log(username+"用户加入聊天室!当前在线:"+count); broadcast(username+"用户加入聊天室!当前在线:"+count); } }else{ broadcast(username+":"+msg); console.log(username+":"+msg); } }); ws.on('close',function(){ delete users[username]; count--; console.log(username+"用户退出聊天室!当前在线:"+count); broadcast(username+"用户退出聊天室!当前在线:"+count); }) });; app.listen(80); //需要广播给所有人(不排除自己) function broadcast(msg){ for(var i in users) users[i].send(JSON.stringify({status:1,info:msg,ischat:true})); }
注意1:express-ws中的ws.send()方法只能发送字符串,并没有express http的res.send()那么强大,故而我在传入js对象时,手动使用JSON.stringify()将对象转换为json字符串,待前端收到后再使用JSON.parse()转换回js对象。
注意2:WebSocket API中几个最重要的事件:open,close,message,error,对应了连接过程中的打开连接,关闭连接,消息传递,错误事件,无论前端还是后端都需要对这几个事件进行绑定监听,传入回掉函数做必要的处理
注意3:设计逻辑再讲一遍:users变量存储每一个连接引用,username作为局部变量,再每一次连接域内部,每一个客户端连入都会创建一个,单独的broadcast()方法遍历所有socket连接发送消息,最后再提醒一遍node.js开发一定要特别注意作用域范围!
效果
相关文章推荐
- 将js进行到底:node学习8
- 将js进行到底:node学习4
- 将js进行到底:node学习6
- 将js进行到底:node学习1
- 将js进行到底:node学习9
- 将js进行到底:node学习10
- 将js进行到底:node学习2
- 将js进行到底:node学习3
- 将js进行到底:node学习5
- 了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发)
- 了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发)
- [将免费进行到底]在Amazon的一年免费服务器上安装Node.JS, NPM和OurJS博客
- [将免费进行到底]在Amazon的一年免费服务器上安装Node.JS, NPM和OurJS博客
- 大熊君大话NodeJS之开篇------Why NodeJS(将Javascript进行到底)
- 了不起的Node.js: 将JavaScript进行到底
- 如何系统地学习Node.js?
- node.js学习第3天,mongos 连接MongoDB
- node.js开发之学习笔记(一)
- Node.js 学习笔记
- 学习笔记-NODE.JS, EXPRESS, JADE, AND MONGODB