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 = 0
      setInterval(() => {
        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 = 0
      setInterval(() => {
        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.mfbz.cn/a/307718.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【mysql】—— 用户管理

目录 &#xff08;一&#xff09;为什么要有用户管理&#xff1f; &#xff08;二&#xff09;用户 2.1 查看用户信息 2.2 创建用户 2.3 删除用户 2.4 修改用户密码 &#xff08;三&#xff09;数据库的权限 3.1 给用户授权 3.2 回收权限 &#xff08;一&#xff09;为…

SEO 分步教程:初学者掌握的 8 个简单基础知识

如果您刚刚开始使用搜索引擎优化 &#xff08;SEO&#xff09;&#xff0c;那么分步 SEO 教程是有序的。在这一点上&#xff0c;你可能已经听说过一些基本术语&#xff0c;如关键词研究和页面优化。但是&#xff0c;您如何应用迄今为止收集的所有知识呢&#xff1f; 如果您刚刚…

EndNote20 下载与安装详细教程

扫描文末二维码&#xff0c;关注微信公众号&#xff1a;ThsPool 后台回复 a004 &#xff0c;免费领取 EndNote20下载安装包 EndNote是一款备受欢迎的文献管理软件&#xff0c;被数百万研究人员、学生和图书管理员广泛使用。它提供便捷的方式来扩展各种语言的参考书目&#xff0…

计算机网络——应用层(2)

计算机网络——应用层&#xff08;2&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) Web和HTTP概念解读HTTPHTTP请求和响应包含内容常见的请求方法Web缓存优点缺点 总结 DNS提供的服务 小程一言 我的计算机网络专栏&#xff0c;是自己在计算机网络学习过程…

鸿蒙系列--属性动画

一、定义 当组件的通用属性发生改变时而产生的属性渐变效果 说明&#xff1a; 当组件的通用属性发生改变时&#xff0c;组件状态由初始状态逐渐变为结束状态的过程中&#xff0c;会创建多个连续的中间状态&#xff0c;逐帧播放后&#xff0c;就会形成动画 二、创建 给组件(如…

智能时代:自然语言生成SQL与知识图谱问答实战

语义解析 前言语义解析的应用场景总结概论语义解析和大模型的关系延伸阅读 前言 语义解析技术可以提高人机交互的效率和准确性&#xff0c;在自然语言处理、数据分析、智能客服、智能家居等领域都有广泛的应用前景。特别是在大数据时代&#xff0c;语义解析能够帮助企业更快速…

k8s的node亲和性和pod亲和性和反亲和性 污点 cordon drain

node亲和性和pod亲和性和反亲和性 污点 cordon drain 集群调度: schedule的调度算法 预算策略 过滤出合适的节点 优先策略 选择部署的节点 nodeName:硬匹配&#xff0c;不走调度策略&#xff0c;node01 nodeSelector:根据节点的标签选择&#xff0c;会走调度的算法 只…

Mac M1 Parallels CentOS7.9 Deploy Docker + Rancher + K8S(HA+More Master)

一、准备虚拟机资源 虚拟机清单 机器名称IP地址角色rancher10.211.55.200管理K8S集群k8svip10.211.55.199K8S VIPmaster0110.211.55.201K8S集群主节点master0210.211.55.202K8S集群主节点master0310.211.55.203K8S集群主节点node0110.211.55.211K8S集群从节点node0210.211.55…

ChatGPT扩展系列之网易数帆ChatBI

在当今数字化快速发展的时代,数据已经成为业务经营与管理决策的核心驱要素。无论是跨国大企业还是新兴创业公司,正确、迅速地洞察数据已经变得至关重要。然而,传统的BI工具往往对用户有一定的技术门槛,需要熟练的操作技能和复杂的查询语句,这使得大部分的企业员工难以深入…

Hadoop分布式文件系统(二)

目录 一、Hadoop 1、文件系统 1.1、文件系统定义 1.2、传统常见的文件系统 1.3、文件系统中的重要概念 1.4、海量数据存储遇到的问题 1.5、分布式存储系统的核心属性及功能含义 2、HDFS 2.1、HDFS简介 2.2、HDFS设计目标 2.3、HDFS应用场景 2.4、HDFS重要特性 2.4…

C++与Typescript的区别

目录 一、C类模板和函数模板 1.类模板 2.函数模板 二&#xff0c;Typescript 的泛型声明 1.泛型函数 2.泛型类 为什么C和Typescript语言中主张模板和泛型 一、C类模板和函数模板 在C中&#xff0c;类模板和函数模板允许你为多种数据类型编写通用的代码。这就像每个人都有…

PSoc62™开发板之PWM呼吸灯

实验目的 利用PWM动态调节输出功率达到控制LED呼吸变化的效果 实验准备 PSoc62™开发板&#xff08;开发板已经板载LED&#xff09; 板载资源 板载有多少pwm 创建工程例程&#xff0c;在libraries/HAL_Drivers/drv_pwm.h中查看BSP支持的pwm数量及对应的GPIO&#xff0c;可…

自动修复vcruntime140.dll丢失的解决办法,快速解决dll文件问题

在使用电脑时也会有不少用户都遇到vcruntime140.dll丢失的情况&#xff0c;那么有什么办法可以解决vcruntime140.dll丢失呢&#xff1f;今天将给大家分享一些关于vcruntime140.dll丢失的解决办法&#xff0c;从自动修复和手动修复两个方向给大家分析希望能够帮助到大家。 一.vc…

基于 Validator 类实现 ParamValidator,用于校验函数参数

目录 一、前置说明1、总体目录2、相关回顾3、本节目标 二、操作步骤1、项目目录2、代码实现3、测试代码4、日志输出 三、后置说明1、要点小结2、下节准备 一、前置说明 1、总体目录 《 pyparamvalidate 参数校验器&#xff0c;从编码到发布全过程》 2、相关回顾 使用 TypeV…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -投票创建后端实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

系列四十六、idea中安装Tomcat7插件

一、idea中安装Tomcat7插件 1.1、描述 学习SpringMVC开发时&#xff0c;代码写完之后&#xff0c;一般会配置一个外置的Tomcat用于启动容器&#xff0c;其实还可以通过插件的方式进行启动&#xff0c;这样就不用再配置外部的Tomcat了&#xff0c;具体怎么配置的呢&#xff1f;…

Spring Cloud + Vue前后端分离-第11章 用户管理与登录

源代码在GitHub - 629y/course: Spring Cloud Vue前后端分离-在线课程 Spring Cloud Vue前后端分离-第11章 用户管理与登录 11-1 增加用户管理功能 用户表设计与基本代码生成 1.用户管理与登录&#xff1a;用户表设计与基本代码生成 all.sql generatorConfig.xml Server…

网络编程套接字(Socket)

文章目录 1 重点知识2 预备知识2.1 理解源IP地址和目的IP地址2.2 认识端口号2.3 理解 "端口号" 和 "进程ID"2.4 理解源端口号和目的端口号2.5 认识TCP协议2.6 认识UDP协议2.7 网络字节序 3 socket编程接口3.1 socket 常见API3.2 sockaddr结构 4 简单的UDP网…

安卓(雷电)模拟器清除屏幕密码

1、设置磁盘可写 启动模拟器&#xff0c;然后在模拟器的设置界面&#xff0c;设置磁盘共享为可写入&#xff0c;重启模拟器&#xff0c;如下图&#xff1a; 2、找到模拟器目录 返回桌面&#xff0c;右键模拟器图标&#xff0c;打开文件所在目录&#xff0c;如下图&#xff1a…

应用在植物生长照明中的LED照明灯珠

植物照明是指利用LED植物照明灯来促进植物生长。植物照明一般采用LED植物生长灯&#xff0c;是一种以LED&#xff08;发光二极管&#xff09;为发光体&#xff0c;满足植物光合作用所需光照条件的人造光源。LED植物生长灯对植物的生长有很大的好处&#xff0c;能促进壮根、助长…
最新文章