websocket: 了解并利用nodejs实现webSocket前后端通信

目录

第一章 前言

1.1 起源

1.2 短轮询与长轮询

1.2.1 短轮询

1.2.2 长轮询

1.2.3 长连接(SSE)

1.2.4 websocket

第二章 利用Node以及ws创建webSocket服务器

2.1 创建ws服务器(后端部分)

2.1.1 了解一下

2.1.2 代创建WebSocket服务器

2.1.3 监听前端连接websocket(ws.on的connection事件)

2.1.4 服务器接收数据(ws.on的message事件)

2.1.5 服务器发送数据(ws.send()方法)

2.1.6 关闭服务器(ws.on的close事件)

2.2 创建后台服务器(后端部分)

第三章 前端使用websocket的方法

3.1 常用的使用方法(前端部分)

3.1.1 代码引入

3.1.2 引入ws

3.1.3 打开ws连接(ws.onopen)

3.1.4 连接错误(ws.onerror)

3.1.5 前端接收服务器的数据(ws.onmessage)

3.1.6 关闭连接(ws.onclose)

第四章 效果展示

提示

源代码


第一章 前言

1.1 起源

在 Web 开发领域,我们最常用的协议是 HTTP,HTTP 协议和 WS 协议都是基于 TCP 所做的封装,但是 HTTP 协议它是从一开始便被设计成请求 -> 响应的模式,所以在很长一段时间内 HTTP 都是只能从客户端发向服务端并不具备从服务端主动推送消息的功能,这也导致在浏览器端想要做到服务器主动推送的效果只能用一些轮询和长轮询的方案来做,但因为它们并不是真正的全双工,所以在消耗资源多的同时,实时性也没理想中那么好。

1.2 短轮询与长轮询

1.2.1 短轮询

  • 解释:前端(客户端)利用循环定时器不断的向后台做HTTP请求(会产生多个HTTP请求),后台(服务端)接到请求后返回响应信息的一种方式
  • 适用于:适用于小型应用,或者同时在线人数较少的应用
  • 优点:简单省时,后端程序编写比较容易(几乎不用做什么特殊处理)
  • 缺点:不及时(得看定时器的间隔),消耗大 ( 服务器宽带和资源)

1.2.2 长轮询

  • 解释:长轮询只启动一个HTTP请求,其连接的服务端会挂起此次连接,后端定时器去查询数据库有没有新消息,直到有新消息才返回响应信息客户端处理完响应信息后再向服务器发送新的Http请求,以此类推。区别于轮询的就是没有新消息就不会发送新的请求
  • 适用于:适用于小型应用,或者同时在线人数较少的应用
  • 优点:可实现实时数据回传,长轮询和轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。
  • 缺点:连接挂起也会导致资源的浪费(服务器压力大,频繁操作询问数据库有没有新结果)

1.2.3 长连接(SSE)

  • SSE是HTML5新增的功能,SSE(sever-sent events)服务器端推送事件,是指服务器推送数据给客户端,而不是传统的请求响应模式。简单的说,就是浏览器向服务器发送一个HTTP请求然后服务器不断单向地向浏览器推送“信息”而SSE最大的特点就是可以实现只要服务器端数据有更新,就可以马上发送到客户端。

1.2.4 websocket

  • websocket 最大的特点就是可以全双工的双向通信
  • 全双工:全双工是指两方能同时发送和接收数据
  • 半双工:半双工是指传输过程中只能向一个方向传输
  • 传输的消息类型:
  1. 文本消息(string)
  2. 二进制消息
  3. 分片消息(分片消息代表此消息是一个某个消息中的一部分,想想大文件分片)
  4. 连接关闭消息
  5. PING 消息
  6. PONG 消息(PING的回复就是PONG)

WebSocket 教程 - 阮一峰的网络日志

第二章 利用Node以及ws创建webSocket服务器

2.1 创建ws服务器(后端部分)

2.1.1 了解一下

  • Node.js原生API没有提供对WebSocket的支持,需要安装第三方包ws才能使用WebSocket功能
  • ws模块:是一个用于支持WebSocket客户端和服务器的框架。它易于使用,功能强大,且不依赖于其他环境
  • 安装
npm install ws

2.1.2 代创建WebSocket服务器

const WebSocket = require('ws')
// 创建WebSocket服务端的对象,绑定的端口号是9998
// 相当于为ws创建了个接口,这个就是连接websocket的链接,后续前端会用到
const wss = new WebSocket.Server({port: 9998
})

2.1.3 监听前端连接websocket(ws.on的connection事件)

const WebSocket = require('ws')
// 创建WebSocket服务端的对象,绑定的端口号是9998
const wss = new WebSocket.Server({port: 9998
})
module.exports.listener = () => {// 对客户端连接事件进行监听,只要有WebSocket连接到该服务器,就会触发'connection'事件// ws代表的是客户端的连接的socket对象;req对象可以用来获取客户端的信息,如ip、端口号wss.on('connection', (ws, req) => {console.log('有客户端连接成功了', ws, req)})
}
// 若要获取所有已连接的客户端信息,则可以使用server.clients数据集

2.1.4 服务器接收数据(ws.on的message事件)

const WebSocket = require('ws')
// 创建WebSocket服务端的对象,绑定的端口号是9998
const wss = new WebSocket.Server({port: 9998
})
module.exports.listener = () => {wss.on('connection', (ws, req) => {console.log('有客户端连接成功了', ws, req)// 对客户端的连接对象进行message事件的监听// 当客户端有消息发送给服务器时,服务器就能够触发该消息// msg:由客户端发给服务端的数据ws.on('message', msg => {console.log('客户端发送给服务器端', msg)// 当接收到客户端传的参数之后服务器端可以执行某些操作(具体看需求)// 小编这里是做了一个数据返回给客户端// 是当客户端连接成功之后会发送一条信息告诉服务器,服务器监听到信息之后再返回数据给客户端const data = [[80, 110, 150, 60, 30, 130, 110],[80, 120, 150, 80, 40, 120, 112],[80, 130, 150, 40, 70, 133, 115],[80, 140, 150, 30, 80, 110, 110],[80, 130, 150, 70, 100, 140, 115],[80, 120, 180, 90, 90, 150, 120],[80, 100, 120, 90, 80, 120, 160]]let i = 0setInterval(() => {if (i === data.length) {i = 0}// 发送数据给客户端ws.send(JSON.stringify(data[i]))i++}, 1000)// 由服务端往客户端发送数据})})
}

2.1.5 服务器发送数据(ws.send()方法)

 /* send(data [,options][,callback])data:发送的数据options对象(可选):(1)compress:指定数据是否需要压缩。默认为true(2)binary:指定数据是否通过二进制传送。默认是自动检测(3)mask:指定是否应遮罩数据。(4)fin:指定数据是否为消息的最后一个片段。默认为true*/
const WebSocket = require('ws')
// 创建WebSocket服务端的对象,绑定的端口号是9998
const wss = new WebSocket.Server({port: 9998
})
const WebSocket = require('ws')
// 创建WebSocket服务端的对象,绑定的端口号是9998
const wss = new WebSocket.Server({port: 9998
})
module.exports.listener = () => {wss.on('connection', (ws, req) => {console.log('有客户端连接成功了', ws, req)// 对客户端的连接对象进行message事件的监听// 当客户端有消息发送给服务器时,服务器就能够触发该消息// msg:由客户端发给服务端的数据ws.on('message', msg => {console.log('客户端发送给服务器端', msg)// 当接收到客户端传的参数之后服务器端可以执行某些操作(具体看需求)// 小编这里是做了一个数据返回给客户端// 是当客户端连接成功之后会发送一条信息告诉服务器,服务器监听到信息之后再返回数据给客户端const data = [[80, 110, 150, 60, 30, 130, 110],[80, 120, 150, 80, 40, 120, 112],[80, 130, 150, 40, 70, 133, 115],[80, 140, 150, 30, 80, 110, 110],[80, 130, 150, 70, 100, 140, 115],[80, 120, 180, 90, 90, 150, 120],[80, 100, 120, 90, 80, 120, 160]]let i = 0setInterval(() => {if (i === data.length) {i = 0}// ========发送数据给客户端========ws.send(JSON.stringify(data[i]))i++}, 1000)// 由服务端往客户端发送数据})})
}

2.1.6 关闭服务器(ws.on的close事件)

const WebSocket = require('ws')
// 创建WebSocket服务端的对象,绑定的端口号是9998
const wss = new WebSocket.Server({port: 9998
})
module.exports.listener = () => {wss.on('connection', (ws, req) => {ws.on('message', msg => {console.log('客户端发送给服务器端', msg.toString('utf8'))const data = [[80, 110, 150, 60, 30, 130, 110],[80, 120, 150, 80, 40, 120, 112],[80, 130, 150, 40, 70, 133, 115],[80, 140, 150, 30, 80, 110, 110],[80, 130, 150, 70, 100, 140, 115],[80, 120, 180, 90, 90, 150, 120],[80, 100, 120, 90, 80, 120, 160]]let i = 0// 模拟了由服务端往客户端发送数据setInterval(() => {if (i === data.length) {i = 0}// 服务器向前端发送数据ws.send(JSON.stringify(data[i]))i++}, 1000)})// 监听要关闭连接的函数ws.on('close', function close () {// 这里面关闭的逻辑console.log('WebSocket连接已关闭')})})
}

—— 至此,后端的websocket逻辑其实已经完结了

2.2 创建后台服务器(后端部分)

  • 利用express框架在后台开服务器,供我们运行后端代码以及跑websocket
// express具体使用看我提供个文章中有
const express = require('express')
const app = express()
const port = 3001
// app.get('/', (req, res) => res.send('hello express'))
// express提供了一个非常好用的函数,叫做express.static(),能快速托管静态资源的内置中间件
// 如下配置是将public目录下的图片、css文件、JavaScript文件对外开放访问
app.use('/', express.static('public'))
// 解析 JSON 格式的请求体数据
app.use(express.json())
// 监听设置的端口
app.listen(port, () => { console.log('server is running,port is' + port) })// 监听开启的websocket服务器
const websocketservice = require('./web_socket_service')
websocketservice.listener()

AJAX及其相关知识应用(很详细)_使用ajax需要引入什么-CSDN博客

第三章 前端使用websocket的方法

3.1 常用的使用方法(前端部分)

(注意:小编这里使用的是一个echarts可视化的动态展示,也方便以后大家使用可视化大屏时有一定的参考价值)

3.1.1 代码引入

<template><div><div id='main' style="width:800px;height:600px"></div></div></template><script>
import * as echarts from 'echarts'
// 引入ws,路径是后端配置好给前端的
const ws = new WebSocket('ws://localhost:9998')
export default {data () {return {}},mounted () {// 要想展示实时效果,需要对series配置下的data数据进行实时的监听const options = {title: {text: '数量统计'},xAxis: {data: ['衣服', '牛奶', '巧克力', '矿泉水', '方便面', '面包', '花生']},yAxis: {},series: [{name: '销量',type: 'line',data: [100, 150, 120, 90, 30, 130, 110]}]}const mychart = echarts.init(document.getElementById('main'))ws.onopen = () => {console.log('连接服务器端成功')ws.send('Hello websocket')}ws.onerror = () => {console.log('连接服务器失败')}ws.onmessage = (msg) => {console.log('接收到服务端发送的数据')console.log('msg', msg)console.log(JSON.parse(msg.data))options.series[0].data = JSON.parse(msg.data)mychart.setOption(options)// ws.send('Hello websocket to message')}},beforeDestroy () {ws.onclose = () => {console.log('websocket已关闭')}},components: {}
}
</script>

3.1.2 引入ws

  • 如果做前后端分分离的项目前端只需要跟后端要配置好的ws的路径即可 
<template><div><div id='main' style="width:800px;height:600px"></div></div></template><script>
import * as echarts from 'echarts'
// 引入ws,路径是后端配置好给前端的
// 小编在这里引入的目的是除了要展示连接成功,还需要执行关闭连接的逻辑,两者不在相同的生命周期钩子中执行
const ws = new WebSocket('ws://localhost:9998')export default {data () {return {}},mounted () {},beforeDestroy () {},components: {}
}
</script>

3.1.3 打开ws连接(ws.onopen)

// 打开连接
ws.onopen = () => {console.log('连接服务器端成功')// 如果与ws连接成功,我们发送消息跟服务器说一下已经连接ws.send('Hello websocket')
}

3.1.4 连接错误(ws.onerror)

ws.onerror = () => {console.log('连接服务器失败')
}

3.1.5 前端接收服务器的数据(ws.onmessage)

// 接收服务器传的数据,msg,每当数据发生变化,后端都会返回数据到前端
// 该方法会一直都在监听ws返回的数据,然后不断的更新我的的图表,从而模拟实现了一个websocket的demo
ws.onmessage = (msg) => {console.log('接收到服务端发送的数据')console.log('msg', msg)// 这里面就可以处理数据的逻辑了console.log(JSON.parse(msg.data))options.series[0].data = JSON.parse(msg.data)mychart.setOption(options)
}

3.1.6 关闭连接(ws.onclose)

beforeDestroy () {ws.onclose = () => {console.log('websocket已关闭')}
},

-- 至此,前端代码结束

第四章 效果展示

  • 启动后端,开启ws服务器

  • 启动前端

  •  运行后前端控制台展示

  •  后端控制台输出

  • 关闭前端页面后台输出

  •  注意代码:msg.toString('utf8')——注意一下websocket支持的数据类型,由于小编看到在控制台输出的是buffer格式,所以进行了一下转换
  • 展示效果 

提示

看到最后了,提示一下,如果还是前后端分开开发时,前端处理其实并没有那么复杂,只需要了解第三章的结构即可。 

源代码

https://gitee.com/shallow-winds/websocket_demo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/337983.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pytorch从零开始实战16

Pytorch从零开始实战——ResNeXt-50算法的思考 本系列来源于365天深度学习训练营 原作者K同学 对于上次ResNeXt-50算法&#xff0c;我们同样有基于TensorFlow的实现。具体代码如下。 引入头文件 import numpy as np from tensorflow.keras.preprocessing.image import Ima…

【昕宝爸爸定制】如何将集合变成线程安全的?

如何将集合变成线程安全的? ✅典型解析&#x1f7e2;拓展知识仓☑️Java中都有哪些线程安全的集合&#xff1f;&#x1f7e0;线程安全集合类的优缺点是什么&#x1f7e1;如何选择合适的线程安全集合类☑️如何解决线程安全集合类并发冲突问题✔️乐观锁实现方式 (具体步骤)。✅…

2024年了,Layui再战三年有问题不?

v2.9.3 2023-12-31 2023 收官。 form 优化 input 组件圆角时后缀存在方框的问题 #1467 bxjt123优化 select 搜索面板打开逻辑&#xff0c;以适配文字直接粘贴触发搜索的情况 #1498 Sight-wcgtable 修复非常规列设置 field 表头选项时&#xff0c;导出 excel 出现合计行错位的…

[Python办公自动化 – 数据预处理和数据校验

Python办公自动化 – 以下是往期的文章目录&#xff0c;需要可以查看哦。 Python办公自动化 – Excel和Word的操作运用 Python办公自动化 – Python发送电子邮件和Outlook的集成 Python办公自动化 – 对PDF文档和PPT文档的处理 Python办公自动化 – 对Excel文档和数据库的操作…

【C++】STL 算法 ③ ( 函数对象中存储状态 | 函数对象作为参数传递时值传递问题 | for_each 算法的 函数对象 参数是值传递 )

文章目录 一、函数对象中存储状态1、函数对象中存储状态简介2、示例分析 二、函数对象作为参数传递时值传递问题1、for_each 算法的 函数对象 参数是值传递2、代码示例 - for_each 函数的 函数对象 参数在外部不保留状态3、代码示例 - for_each 函数的 函数对象 返回值 一、函数…

中小企业低成本如何进行推广?媒介盒子解答

数字化时代下&#xff0c;用户想要购买产品的第一步都是在网上查询相关信息&#xff0c;因此对于中小企业来说&#xff0c;怎么把自己曝光到网上&#xff0c;怎么可以让用户搜到类似关键词时名列其中是企业需要考虑的问题&#xff0c;今天媒介盒子就来和大家聊聊&#xff1a;中…

五、Spring AOP面向切面编程(基于XML方式实现)

本章概要 Spring AOP基于XML方式实现(了解)Spring AOP对获取Bean的影响理解 根据类型装配 bean使用总结 5.6 Spring AOP基于XML方式实现(了解) 准备工作 加入依赖 <!-- spring-aspects会帮我们传递过来aspectjweaver --> <dependency><groupId>org.spr…

代理IP连接不上/网速过慢?如何应对?

当您使用代理时&#xff0c;您可能会遇到不同的代理错误代码显示代理IP连不通、访问失败、网速过慢等种种问题。 在本文中中&#xff0c;我们将讨论您在使用代理IP时可能遇到的常见错误、发生这些错误的原因以及解决方法。 一、常见代理服务器错误 当您尝试访问网站时&#…

10个最容易被忽视的 FastAPI 实用功能

FastAPI是一种现代、高性能的Python Web框架&#xff0c;用于构建Web应用程序和API。 它基于Python的异步编程库asyncio和await语法&#xff0c;以及类型注解和自动文档生成等特性&#xff0c;提供了快速、易用和可靠的开发体验&#xff0c;接下来本文将介绍10项被忽视的FastA…

Qt/QML编程学习之心得:hicar手机投屏到车机中控的实现(32)

hicar,是华为推出的一款手机APP,有百度地图、华为音乐,更多应用中还有很多对应手机上装在的其他APP,都可以在这个里面打开使用,对开车的司机非常友好。但它不仅仅是用在手机上,它还可以投屏到车机中控上,这是比较神奇的一点。 HiCar本质上是一套智能投屏系统,理论上所有…

React Native 桥接原生常量

一、编写并注册原生常量方法 在 SmallDaysAppModule 这个模块中有一个方法 getConstans &#xff0c;重载这个方法就可将自定义的常量返回&#xff0c;系统会自行调用该方法并返回定义的常量将其直接注入到 JS 层&#xff0c;在 JS 层直接获取即可。 二、JS 层获取原生常量&am…

Vulnhub靶机:Corrosion1

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;corrosion:1&#xff08;10.0.2.12&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/c…