首页 > 其他分享 >学习websocket,原来这么简单

学习websocket,原来这么简单

时间:2023-06-26 11:37:07浏览次数:38  
标签:websocket console 学习 wss ws 简单 WebSocket 连接 客户端

简单介绍 websocket

WebSocket是一种在TCP连接上进行全双工通信的协议。
WebSocket通信协议于2011年被IETF定为标准。
然后WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,
允许服务端主动向客户端推送数据。
在WebSocket API中,浏览器和服务器只需要完成一次握手。
两者之间就直接可以创建持久性的连接,并进行双向数据传输。

我们为什么要使用 websocket

我们都知道 HTTP 协议有一个缺陷。
那就是通信只能由客户端发起。服务端没法主动发起。
有些场景我们需要让客户端实时知道消息。
虽然可以使用轮询来解决这个问题。
但是非常浪费资源,因为要不停连接,断开后又继续连接。
这个时候我们就需要使用 websocket

websocket 应用场景

1.弹幕媒体聊天 [客服推送]
2.协同编辑 [wps]
3.基于位置的应用 [外卖]
4.体育实况更新
5.股票帮金报价实时更新

websocket 和HTTP请求的不同点:

1.WebSocket是双向通信协议,HTTP是单向的
WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。而HTTP是单向的

2.连接方式不同
WebSocket是需要浏览器和服务器握手进行建立连接的。
http是浏览器发起向服务器的连接,服务器预先并不知道这个连接。

3.协议开头不同
websocket:websocket的协议是以 ws/wss 开头。
http 对应的是 http/https

4.连接长度不同
websocket是持久连接。http 是短连接。

简单实现一下 WebSocket

node创建WebSocket
我们需要先下载 npm install ws
ws是一个简单易用、快速且经过全面测试的WebSocket客户端和服务器实现。
我们就直接使用就好了
const express = require('express')
const app = express()
const port = 3000
// 托管静态资源-express.static()
app.use(express.static('public'))
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

// 引入 ws,并且解构使用我们需要的 WebSocketServer        
const { WebSocketServer } = require('ws');
// 创建WebSocketServer的实例wss,并指定端口号
const wss = new WebSocketServer({ port: 8080 });
// 通过实例wss进行监听
wss.on('connection', function connection(ws) {
  ws.on('error', console.error);
  // 接收客户端发送过来的消息
  ws.on('message', function message(data) {
    console.log('客户端发送过来的消息', data);
  });
  ws.send('服务端发送的消息');
});
客户端 WebSocket 的创建
我们需要创建 WebSocket 的实例同时指定端口号。
然后通过 onopen  onmessage one rror 来判断ws的状态事件
下面我们就来简单写一下
<body>
    <h1>欢迎 学习WebSocket </h1>
</body>
<script>
// 创建 WebSocket并指定一个地址
let ws = new WebSocket('ws://localhost:8080')
// 是否链接成功
ws.onopen = (() => {
  console.log("链接成功")
})
// 监听服务端发送过来的消息
ws.onmessage = ((messObj) => {
  console.log('发送过来的消息', messObj)
})
// 连接失败
ws.onerror = (() => {
  console.log('连接失败')
})
</script>

客户端发送消息给服务端

我们需要写一个简单的html界面,
获取到 文本域中的内容。
然后通过 ws.send(textareaValue) 给服务端发送消息。
服务端在 
ws.on('message', function message(data) {
  console.log(data)
}) 
这个方法中接收客户端的消息
data就是客户端发送过来的消息
如果是二进制数据,我们可以使用 data.toString()进行转换
<body>
    <h1>欢迎 学习WebSocket </h1>
    <textarea rows="10" cols="30" id="textarea" placeholder="请输入内容"></textarea>
    <button onclick="sendHandler()">点击按钮</button>
</body>

// 创建 WebSocket并指定一个地址
let ws = new WebSocket('ws://localhost:8080')

let textarea=document.getElementById('textarea')
function sendHandler(){
  const textareaValue = textarea.value;
  // 通过ws.send给客户端发送消息
  ws.send(textareaValue)
}

WebSocket 实现广播

我们要做一个广播。
就有点类似在QQ群中发送一条消息,
在这个群中的其他用户可以接收到这条消息。
WebSocket 连接成功后,wss.clients来获取当前服务端连接了多少个客户端。
wss.clients是一个Set类型的。我们通过 forEach 来进行遍历。
我们通过 client.readyState 的状态是否是 WebSocket.OPEN
然后调用 client.send(data, { binary:false  })就数据发送出去
// 引入 ws,并且解构使用我们需要的 WebSocketServer        
const { WebSocketServer, WebSocket } = require('ws');
// import { WebSocketServer } from 'ws';
// 创建WebSocketServer的实例wss,并指定端口号
const wss = new WebSocketServer({ port: 8080 });
// 通过实例wss进行监听
wss.on('connection', function connection(ws) {
  ws.on('error', console.error);
  // 客户端
  ws.on('message', function message(data) {
    console.log('received: %s', data);
    // 服务器广播
    // 广播到所有连接的WebSocket客户端,包括其自身。
    console.log('连接了多少个',wss.clients.size)
    wss.clients.forEach(function each(client) {
      // 判断当前连接服务端的所有客户端的ws。
      if (client.readyState === WebSocket.OPEN) {
        // binary表示数据是否是二进制。binary:false表示不是二进制
        client.send(data, { binary:false  });
      }
    });
  });
  ws.send('服务端发送的消息');
});

发现自己也被广播了

假设不同的浏览器代码一个用户。
通过上面的图片,我们发现谷歌浏览器发送一条消息。
虽然火狐浏览器接收到了。但是谷歌发送的消息自己也接收到了。
这样明显是不正确的。因此。我们处理一下。
自己发送的消息不需要广播自己的。
我们使用 client!==ws 来进行判断
// 引入 ws,并且解构使用我们需要的 WebSocketServer        
const { WebSocketServer, WebSocket } = require('ws');
// import { WebSocketServer } from 'ws';
// 创建WebSocketServer的实例wss,并指定端口号
const wss = new WebSocketServer({ port: 8080 });
// 通过实例wss进行监听
wss.on('connection', function connection(ws) {
  ws.on('error', console.error);
  // 客户端
  ws.on('message', function message(data) {
    console.log('received: %s', data);
    // 服务器广播
    // 广播到所有连接的WebSocket客户端,包括其自身。
    console.log('连接了多少个',wss.clients.size)
    wss.clients.forEach(function each(client) {
      // 判断当前连接服务端的所有客户端的ws用户。
      // client!==ws 表示不是当前发送的用户[不要自己广播自己]
      if (client!==ws && client.readyState === WebSocket.OPEN) {
        // binary表示数据是否是二进制。binary:false表示不是二进制
        client.send(data, { binary:false  });
      }
    });
  });
  // 第一次连接成功后发送的消息。
  ws.send('');
});

实现关闭页面关闭 WebSocket

当我们离开连接 WebSocket的页面离开后,
我们应该关闭当前连接。
可是现在我们点击去user页面的时候,并没有关闭连接。
这显然是不太好的。所以我们需要优化一下。
当用户离开,我们需要关闭连接
// 关闭当前窗口,按下 F5 或点击以下链接触发 onbeforeunload 事件
document.body.onbeforeunload = function () {
  ws.close()
  return 'close'
}

//离开当前页面会触发
window.onunload = function (e) {
  var e = window.event || e;
  console.log('===>',e)
  // 离开页面,关闭WebSocket
  ws.close()
}

携带token

我们在连接 WebSocket 的时候,
没有鉴权,也就是说无法判断当前这个用户的信息。
这样是不安全的。
因此我们在连接 WebSocket 需要携带token.
通过这样的形式携带  ws://localhost:8080?token=' + 'tokne_zahngsan'
// 创建 WebSocket并指定一个地址,并且携带一个token
let ws = new WebSocket('ws://localhost:8080?token=' + 'tokne_zahngsan')
//省略其他代码
wss.on('connection', function connection(ws,req) {
  // 获取前端携带的token
  console.log('req', req.url.slice(8))
})


标签:websocket,console,学习,wss,ws,简单,WebSocket,连接,客户端
From: https://www.cnblogs.com/IwishIcould/p/17501820.html

相关文章

  • 【网络】【HTTP】既然有 HTTP 协议,为什么还要有 WebSocket?
    1  前言平时我们打开网页,比如购物网站某宝。都是点一下「列表商品」,跳转一下网页就到了「商品详情」。从HTTP协议的角度来看,就是点一下网页上的某个按钮,前端发一次HTTP请求,网站返回一次HTTP响应。这种由客户端主动请求,服务器响应的方式也满足大部分网页的功能场景。但......
  • Java学习笔记(十六)
    1.什么是线程?线程是指操作系统中的一种执行单元,它是进程中的一部分,可以看作是轻量级的进程。与进程不同的是,线程共享同一进程的地址空间和系统资源,如打开文件和信号处理等,但每个线程都有自己的程序计数器(PC)和栈,用于执行代码和存储局部变量等数据。2。线程和进程有什么区别?线......
  • 人生观察语料学习笔记133
    标题記憶喪失の人を騙し続けたら?如果一直欺骗一个失去记忆的人会怎么样呢?きおく(記憶)【名】记忆そうしつ(喪失)【名】丧失ひと(人)【名】人だます(騙す)【他动词・五段/一类】欺骗つづく(続く)【自动词・五段/一类】继续つづ......
  • 李超线段树 学习笔记
    李超线段树学习笔记今天模拟赛用到了李超线段树(但是本蒟蒻费了半天劲搞了个斜率优化拿到了60pts的好成绩/kk),所以学习一下李超线段树刻不容缓(学会了我貌似也切不来那道题qwq)。引入初中和高中我们都做过函数题吧,是不是有时候给你两根甚至几根直线,然后问你某个点的最值?当然,......
  • 「学习笔记」vector
    本文并不是vector的入门教程。定义std::vector是封装动态数组的顺序容器。vector通常占用多于静态数组的空间,因为要分配更多内存以管理将来的增长。如果元素数量已知,可以使用reserve()函数提前分配内存。操作函数由于vector大家比较熟悉了,这里给大家带来一些其他......
  • C语言学习笔记
    斐波那契定义:斐波那契数列是一个数列,其中每个数字是前两个数字之和,起始于0和1。数列的定义如下:F(0)=0F(1)=1F(n)=F(n-1)+F(n-2)(对于n>1)换句话说,斐波那契数列的第n个数字是前两个数字之和,而前两个数字分别是0和1。数列的前几个数字如下所示:0,1,1,......
  • 6月25日java学习日记
    端午节小休息了几天,断开连接了几天,希望快速状态回到吧,今天了解了部分java异常类,Exceptions类为异常类,学习了throw关键字,以及了解了trycatch的用法(基本与C#相同),同时使用HasgMap以及List.of方法实现了斗地主案例。 ......
  • 烧写文件系统——韦东山嵌入式Linux学习笔记11
    原文:https://blog.csdn.net/longintchar/article/details/71319513本文实验环境:1.windows7(64bit)2.JZ2440(V2)使用u-boot烧写文件系统,一般有两种方法。1.通过USB下载功能2.通过TFTP功能通过USB下载功能烧写文件系统这种方法比较简单。操作步骤:(1)连接板子和PC(串口+USB)(2)进入u-......
  • 07前后端项目上传gitee,后端多方式登录接口,发送短信功能,发送短信封装,短信验证码接口,短
    1前后端项目上传到gitee#公司里: -前端一个仓库---》一个团队-后端一个仓库---》一个团队-微服务:两三个人一个服务---》一个项目一个仓库-网上开源软件,前后端都在一起#在远端建立前端仓库#本地代码提交到远成仓库2后端多方式......
  • 学习Java前的一些介绍
    1.java开发环境搭建卸载:删除Java的安装目录删除JAVA_HOME删除path下关于java的目录java-version验证安装:创建jdk和jre两个目录(还可以创建一个code目录存放代码)百度搜索jdk(建议安装jdk8)同意协议,找到对应版本并且下载双击安装jdk配置环境变量我......