学习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 onerror 来判断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,原来这么简单的更多相关文章
- 我在阿里这仨月 前端开发流程 前端进阶的思考 延伸学习的方式很简单:google 一个关键词你能看到十几篇优秀的博文,再这些博文中寻找新的关键字,直到整个大知识点得到突破
我在阿里这仨月 Alibaba 试用期是三个月,转眼三个月过去了,也到了转正述职的时间.回想这三个月做过的事情,很多很杂,但还是有重点. 本文谈一谈工作中遇到的各种场景,需要用到的一些前端知识,以及我 ...
- 如何学习 websocket ?
如何学习 websocket ? 使用 HTML https://github.com/phoboslab/jsmpeg MPEG1 进行播放 https://w3c.github.io/media- ...
- phpunit测试学习 1:一点简单的扼要有用的东西的总结 一点入门认识
16:45 2015/12/8phpunit测试学习 1:一点简单的扼要有用的东西的总结 一点入门认识 具体的入门安装和入门实践请参照文中的推荐博客或网上其他博客推荐博客,我感觉这几篇博客写得很不错 ...
- Quartz定时任务学习(一)简单任务
学习quartz首先了解三个概念: 调度器:负责调度作业和触发器: 触发器:设置作业执行的时间.参数.条件等:(简单触发器和Cron触发器) 作业:定时任务内容,被执行的程序: 下载必要的jar包,直 ...
- WebSocket就是这么简单
前言 今天在慕课网上看到了Java的新教程(Netty入门之WebSocket初体验):https://www.imooc.com/learn/941 WebSocket我是听得很多,没有真正使用过的 ...
- [转]ZooKeeper学习第一期---Zookeeper简单介绍
ZooKeeper学习第一期---Zookeeper简单介绍 http://www.cnblogs.com/sunddenly/p/4033574.html 一.分布式协调技术 在给大家介绍ZooKe ...
- Spring MVC 学习笔记10 —— 实现简单的用户管理(4.3)用户登录显示全局异常信息
</pre>Spring MVC 学习笔记10 -- 实现简单的用户管理(4.3)用户登录--显示全局异常信息<p></p><p></p>& ...
- Spring MVC 学习笔记9 —— 实现简单的用户管理(4)用户登录显示局部异常信息
Spring MVC 学习笔记9 -- 实现简单的用户管理(4.2)用户登录--显示局部异常信息 第二部分:显示局部异常信息,而不是500错误页 1. 写一个方法,把UserException传进来. ...
- Spring MVC 学习笔记8 —— 实现简单的用户管理(4)用户登录
Spring MVC 学习笔记8 -- 实现简单的用户管理(4)用户登录 增删改查,login 1. login.jsp,写在外面,及跟WEB-INF同一级目录,如:ls Webcontent; &g ...
- LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS
LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163. ...
随机推荐
- 时隔十年,QQ更新了Linux版本
昨天1024程序员节,QQ悄悄地更新了QQ for Linux,也许是给各位一个惊喜吧. 官网及其的简陋.和一个Word文档似的. 十年一更,有网友称,瞬间回到QQ2006,确实界面功能有些落后,相信 ...
- [Android]ADB调试: SecurityException: Injecting to another application requires INJECT_EVENTS permission
问题描述 使用ADB工具调试安卓设备时报此错误: C:\Users\Johnny>adb shell input text "Hello" java.lang.Securit ...
- AQS源码学习
抽象队列同步器AQS AQS介绍 AQS提供一套框架用于实现锁同步机制,其通过一个 FIFO队列 维护线程的同步状态,实现类只需要继承 AbstractQueuedSynchronizer ,并重写指 ...
- 无法加载 DLL“xxxx.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。
有一台服务器在执行接口的时候遇到了这样一个问题: 其他服务器上都没有这个问题,IIS部署好的项目目录的bin文件夹下是有这个dll的,但却提示无法加载,在网上找了好多帖子,终于发现了问题. 首先用De ...
- SpringBoot 缓存注解的使用
最近比较忙,没时间更新了.上一篇文章我说了如何使用Redis做缓存,文末我稍微提到了SpringBoot对缓存的支持.本篇文章就针对SpringBoot说一下如何使用. 1.SpringBoot对缓存 ...
- 2023高效的mysql 随机语句 200万数据为例 用了 0.0030秒
是的,如果数据表中有200万条记录,使用 ORDER BY RAND() 这种方式来随机选择记录会非常慢,因为 MySQL 需要对整个表进行排序,然后再返回指定数量的记录.这个过程需要消耗大量的时间和 ...
- 考前必备fa宝——对拍
2022.11.24:晚上zxs学长发来了他的博客,所以我仿照写一篇. https://www.cnblogs.com/Dita/p/duipai.html 对拍 对拍这个东西,就是可以比较两份代码跑 ...
- JavaScript原生兼容大全-持续更新
JavaScript兼容-持续更新 1.css非行内样式操作 // currentStyle用于IE低版本 getComputed用于主流浏览器 // element 目标元素 attribute 目 ...
- 【asp.net core】自定义模型绑定及其验证
引言 水此篇博客,依旧是来自群里的讨论,最后说到了,在方法参数自定义了一个特性,用来绑定模型,优先从Form取,如果为空,或者不存在,在从QueryString中获取并且绑定,然后闲着无聊,就水一篇博 ...
- 文心一言 VS chatgpt (3)-- 算法导论2.1
一.以图 2-2 为模型,说明INSERTION-SORT 在数组 A=(31,41,59,26,41,58)上的执行过程. 文心一言: 以图 2-2 为模型,说明INSERTION-SORT 在数组 ...