热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

node系列:初探websocket

简介很多网站的实时推送技术,所用的技术大多都是Ajax轮询。也就是隔几秒请求一次接口,显然这样会浪费很多的带宽等资源。WebSocket允许服务端主动

简介

很多网站的实时推送技术,所用的技术大多都是 Ajax 轮询。也就是隔几秒请求一次接口,显然这样会浪费很多的带宽等资源。WebSocket 允许服务端主动向客户端推送数据,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

特点


  • 双向通信
  • 没有同源策略(客户端可以与任意服务器通信)
  • 二进制支持

工具

在线测试小工具

客户端实现

function WebSocketTest () {if ("WebSocket" in window) {console.log("您的浏览器支持 WebSocket!");// 打开一个 web socketvar ws = new WebSocket("ws://localhost:9998/echo");ws.onopen = function () {// Web Socket 已连接上,使用 send() 方法发送数据ws.send("发送数据");alert("数据发送中...");};ws.onmessage = function (evt) {var received_msg = evt.data;alert("数据已接收...");};ws.onclose = function () {// 关闭 websocketalert("连接已关闭...");};}else {// 浏览器不支持 WebSocketalert("您的浏览器不支持 WebSocket!");}
}

后台实现(node)

由于原生的node实现起来非常复杂,需要牵扯到一些底层的如数据帧的编码解码,所以我们这里直接用已经实现好的第三方库,比如socket.io,WebSocket-Node

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function (req, res) {res.send('

Welcome Realtime Server

');
});
io.on('connection', function (socket) {console.log('a user connected');socket.on("disconnect", function () {console.log("a user go out");});socket.on("message", function (obj) {io.emit("message", obj);});
});
http.listen(3000, function () {console.log('listening on *:3000');
});


<html lang&#61;"en">
<head><meta charset&#61;"UTF-8"><title>Documenttitle><script src&#61;"http://127.0.0.1:3000/socket.io/socket.io.js">script>
head>
<body><ul id&#61;"message">ul><script>socket &#61; io.connect(&#39;ws://127.0.0.1:3000&#39;);socket.emit("message", {"name" : navigator.userAgent, "msg" : "hello world"});socket.on("message", function(obj) {console.log(obj);});script>
body>
html>

简易的控制台版的聊天室

客户端心跳机制的实现

WebSocket并不稳定&#xff0c;在使用一段时间后&#xff0c;可能会断开连接&#xff0c;貌似至今没有一个为何会断开连接的公论&#xff0c;所以我们需要让WebSocket保持连接状态&#xff0c;这里推荐两种方法。

1、class类中就是用的这种方式:设置一个变量&#xff0c;在webSocket关闭/报错的回调中&#xff0c;判断是不是手动关闭的&#xff0c;如果不是的话&#xff0c;就重新连接&#xff0c;这样做的优缺点如下&#xff1a;

  • 优点&#xff1a;请求较少(相对于心跳连接)&#xff0c;易设置。
  • 缺点&#xff1a;可能会导致丢失数据,在断开重连的这段时间中&#xff0c;恰好双方正在通信。

2、客户端就像心跳一样每隔固定的时间发送一次ping&#xff0c;来告诉服务器&#xff0c;我还活着&#xff0c;而服务器也会返回pong&#xff0c;来告诉客户端&#xff0c;服务器还活着。具体方法再下文注释中。

class WebSocketClass {/*** &#64;description: 初始化实例属性&#xff0c;保存参数* &#64;param {String} url ws的接口* &#64;param {Function} msgCallback 服务器信息的回调传数据给函数* &#64;param {String} name 可选值 用于区分ws&#xff0c;用于debugger*/constructor(url, msgCallback, name &#61; &#39;default&#39;) {this.url &#61; url;this.msgCallback &#61; msgCallback;this.name &#61; name;this.ws &#61; null; // websocket对象this.status &#61; null; // websocket是否关闭}/*** &#64;description: 初始化 连接websocket或重连webSocket时调用* &#64;param {*} 可选值 要传的数据*/connect(data) {// 新建 WebSocket 实例this.ws &#61; new WebSocket(this.url);this.ws.onopen &#61; e &#61;> {// 连接ws成功回调this.status &#61; &#39;open&#39;;console.log(&#96;${this.name}连接成功&#96;, e)// this.heartCheck();if (data !&#61;&#61; undefined) {// 有要传的数据,就发给后端return this.ws.send(data);}}// 监听服务器端返回的信息this.ws.onmessage &#61; e &#61;> {// 把数据传给回调函数&#xff0c;并执行回调// if (e.data &#61;&#61;&#61; &#39;pong&#39;) {// this.pingPong &#61; &#39;pong&#39;; // 服务器端返回pong,修改pingPong的状态// }return this.msgCallback(e.data);}// ws关闭回调this.ws.onclose &#61; e &#61;> {this.closeHandle(e); // 判断是否关闭}// ws出错回调this.onerror &#61; e &#61;> {this.closeHandle(e); // 判断是否关闭}}// heartCheck() {// // 心跳机制的时间可以自己与后端约定// this.pingPong &#61; &#39;ping&#39;; // ws的心跳机制状态值// this.pingInterval &#61; setInterval(() &#61;> {// if (this.ws.readyState &#61;&#61;&#61; 1) {// // 检查ws为链接状态 才可发送// this.ws.send(&#39;ping&#39;); // 客户端发送ping// }// }, 10000)// this.pongInterval &#61; setInterval(() &#61;> {// this.pingPong &#61; false;// if (this.pingPong &#61;&#61;&#61; &#39;ping&#39;) {// this.closeHandle(&#39;pingPong没有改变为pong&#39;); // 没有返回pong 重启webSocket// }// // 重置为ping 若下一次 ping 发送失败 或者pong返回失败(pingPong不会改成pong)&#xff0c;将重启// console.log(&#39;返回pong&#39;)// this.pingPong &#61; &#39;ping&#39;// }, 20000)// }// 发送信息给服务器sendHandle(data) {console.log(&#96;${this.name}发送消息给服务器:&#96;, data)return this.ws.send(data);}closeHandle(e &#61; &#39;err&#39;) {// 因为webSocket并不稳定&#xff0c;规定只能手动关闭(调closeMyself方法)&#xff0c;否则就重连if (this.status !&#61;&#61; &#39;close&#39;) {console.log(&#96;${this.name}断开&#xff0c;重连websocket&#96;, e)// if (this.pingInterval !&#61;&#61; undefined && this.pongInterval !&#61;&#61; undefined) {// // 清除定时器// clearInterval(this.pingInterval);// clearInterval(this.pongInterval);// }this.connect(); // 重连} else {console.log(&#96;${this.name}websocket手动关闭&#96;)}}// 手动关闭WebSocketcloseMyself() {console.log(&#96;关闭${this.name}&#96;)this.status &#61; &#39;close&#39;;return this.ws.close();}
}
function someFn(data) {console.log(&#39;接收服务器消息的回调&#xff1a;&#39;, data);
}
// const wsValue &#61; new WebSocketClass(&#39;ws://121.40.165.18:8800&#39;, someFn, &#39;wsName&#39;); // 这个链接一天只能发送消息50次
const wsValue &#61; new WebSocketClass(&#39;wss://echo.websocket.org&#39;, someFn, &#39;wsName&#39;); // 阮一峰老师教程链接
wsValue.connect(&#39;立即与服务器通信&#39;); // 连接服务器
// setTimeout(() &#61;> {
// wsValue.sendHandle(&#39;传消息给服务器&#39;)
// }, 1000);
// setTimeout(() &#61;> {
// wsValue.closeMyself(); // 关闭ws
// }, 10000)


推荐阅读
  • XMLhttpREquest_Ajax技术总结之XmlHttpRequest
    Ajax1、 什么是ajax   ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
  • Allegro总结:1.防焊层(SolderMask):又称绿油层,PCB非布线层,用于制成丝网印板,将不需要焊接的地方涂上防焊剂.在防焊层上预留的焊盘大小要比实际的焊盘大一些,其差值一般 ... [详细]
  • ASP.NET&Spring.NET&NHibernate最佳实践(五)——第3章人事子系统(2)
    3.4.人事子系统服务层(Service)部门服务接口(IDeptService.cs)usingSystem;usingGuushuuse.SalaryPrj. ... [详细]
author-avatar
闺蜜好我会明白
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有