Web端即时通讯必备技术:WebSocket快速入门
zhezhongyun 2025-01-14 19:06 79 浏览
随着Web应用程序的不断发展,越来越多的应用需要实现实时交互和通信。然而,传统的HTTP协议只支持单向通信,即客户端向服务器发送请求并接收响应。为了解决这一限制,WebSocket技术应运而生。本文将为大家介绍即时通讯技术 WebSocket的基本原理,并且讲解一个基于WebSocket + Node.js实现简易的一对一实时聊天的案例。
一、基本概念
WebSocket是一种HTML5提供的全双工通信协议(指可以在同一时间内允许两个设备之间进行双向发送和接收数据的通信协议),用于浏览器与服务器之间的实时通信。
WebSocket基于TCP传输协议,并且复用HTTP的握手通道(基于HTTP的 "keep-alive" 机制,允许在一次TCP连接中传送多个HTTP请求和响应)。建立WebSocket连接时,客户端会向服务器发送一个HTTP请求报文,其中包含升级协议的请求头,服务器在接收到该请求后会返回一个HTTP响应报文,其中包含升级协议的响应头。在收到服务器的响应后,客户端和服务器之间的连接就会升级为WebSocket连接,此时客户端和服务器之间的通信就不再需要使用HTTP协议的请求和响应报文,而是直接进行双向数据传输。因此,可以大大减少建立和断开连接的开销,并且实现更低的延迟和更高的吞吐量。
下面是它的优点:
1、实时性:与传统的HTTP请求/响应模式不同,WebSocket允许实时双向通信,使得服务器能够主动向客户端推送数据,而不需要客户端发起请求。
2、更少的网络流量:WebSockets使用更少的网络流量,因为在连接建立后,客户端和服务器之间的通信只需要很少的开销。
3、更少的延迟:由于WebSocket允许实时通信,因此它可以大大减少通信的延迟时间。
4、更少的服务器压力:WebSocket连接保持打开状态,因此服务器不需要为每个请求创建一个新的连接。这可以减轻服务器的负载并提高性能。
5、更好的跨域支持:WebSocket具有更好的跨域支持,因为它使用标准的HTTP握手来建立连接,可以使用与HTTP相同的跨域策略。
6、可扩展性:WebSocket可以轻松扩展以支持大量并发连接,因为它使用单个TCP连接来处理多个并发请求。
7、省电:WebSocket可以通过减少网络流量和延迟来减少移动设备的能耗,因此它在移动设备上的使用非常适合。
二、快速上手
步骤说明
WebSocket技术的运用主要分为3个步骤,以下分别说明:
1、建立握手连接客户端向服务器发送一个HTTP请求,其中包含Upgrade头部,表示要升级协议到WebSocket,然后服务器发送回一个带有Upgrade头部的HTTP响应,表示同意升级。接着,客户端和服务器就建立了WebSocket连接。
(1)客户端的请求头主要内容(采用HTTP请求报文格式,并且只支持GET方法)
GET ws://127.0.0.1:57924/2.html/ws HTTP/1.1
Host: 127.0.0.1:57924
Connection: Upgrade
Upgrade: websocket
Origin: http://127.0.0.1:57924
Sec-WebSocket-Key: 2DBoIM6oiUuKvzSmZnjdCA==
说明:
*Connection: Upgrade:Connection表示连接形式,Upgrade是升级的意思
*Upgrade: websocket:表示要升级为websocket协议
(2)服务端的响应头内容
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 85fqPOwals3GjAFetTkCD04AfE4=
说明:返回状态代码101表示协议已切换,完成协议升级。
2、数据传输:建立WebSocket连接之后,客户端和服务器之间可以互相发送消息。WebSocket采用帧的形式进行数据传输,一个帧包含一个或多个数据片段。帧头部包含了帧的元信息,比如数据是否被分片、数据类型等信息。接收方会将关联的帧重新组装成完整的消息。
3、关闭连接:当不再需要连接时进行时,需要关闭的一方通过 ws.close() 方法进行关闭,该方法会发送一个包含关闭码的帧。接收到关闭码后,另一方也会发送一个带有关闭码的响应帧,表示同意关闭连接。
简单实现例子
1、使用Node.js建立WebSocket服务器代码( 这里使用了ws库来创建WebSocket服务器)
// 引入ws库
const WebSocket = require('ws')
// 建立websocket服务器
const server = new WebSocket.Server({ port: 8080 })
// 建立一个空的数据集合users
let users = new Set()
let count = 0
server.on('connection', function (ws) {
/* 每当有新用户连接了该WebSocket服务器,就会建立一个持久化的连接
并触发该函数,除非一方发送关闭帧或发生网络故障才会导致连接中断 */
// ws为当下连接的用户对象,这里把用户信息收集至users集合中
users.add(ws)
//统计进来的用户数
count++
console.log(count + '名用户连接了')
ws.on('message', function (message) {
/* 接收当下用户ws在客户端发送的消息之后,就会触发该函数,
形参message就是发来的信息,此时是二进制的数据 */
users.forEach(function (user) {
// 遍历所有用户,给非自己的其他用户发送消息
if (user !== ws) {
user.send(message.toString())
}
})
})
})
说明:
(1)当建立了一个WebSocket长连接后,会触发server.on('connection',连接函数)的连接函数,参数ws就表示当下的用户,并用users集合来收集用户;
(2)在连接函数里放入 ws.on('message', 消息函数),当该ws用户在客户端发送了消息,就会触发消息函数,形参message是二进制格式的消息;
(3)在消息函数里遍历users集合,给非自身的用户都发送当下ws用户发来的消息。
2、前端简易代码
const ws = new WebSocket('ws://localhost:8080')
ws.onopen = function () {
console.log('与服务器建立了websocket连接')
ws.send('hello') // 建立连接后,立马给服务器发送字符串信息
}
ws.onmessage = function (event) {
console.log('接收到服务端发送的其他用户的消息')
console.log('打印数据' + event.data)
}
说明:
(1)WebSocket是由HTML5提供的技术,所以此处可以直接new WebSocket创建一个连接,连接的协议要改为ws,端口号与服务器建立的要对应;
(2)当建立了连接就会触发ws.onopen事件函数,当接收消息就会触发ws.onmessage事件函数。
三、WebSocket + Node.js实现一对一聊天室
讲到这里大家应该已经了解了WebSocket快速实现的方式,下面我们就为大家讲解如何使用 WebSocket + Node.js 技术来实现简易版的一对一聊天室效果。
前端代码
1、HTML+CSS代码
<style>
#box {
width: 400px;
height: 200px;
overflow-y: scroll;
padding: 10px;
margin-bottom: 20px;
border: 1px solid rgb(156, 152, 152);
background-color: #f8f4f4;
}
/* 放置聊天信息的div,为了消息有左右展示的效率设置了display:flex */
#chat-window {
display: flex;
flex-direction: column;
}
#chat-window > div {
flex-grow: 1;
padding: 5px;
max-width: 70%;
}
#chat-window > div > div {
text-align: left;
word-wrap: break-word;
padding: 5px;
border-radius: 5px;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
}
#chat-window > div > span {
font-size: 12px;
color: #aaa6a6;
}
/* 收到对方发来的消息会动态生成类目为left-message的div标签,并设置左侧展示 */
.left-message {
align-self: flex-start;
}
/* 自己发送消息会动态生成类目为right-message的div标签,并设置右侧展示 */
.right-message {
text-align: right;
align-self: flex-end;
}
.left-message div {
background-color: #fff;
}
.right-message div {
background-color: #4dc86f;
}
</style>
<body>
<h3>一对一聊天室</h3>
<div id="box">
<div id="chat-window"></div>
</div>
<input type="text" id="message" placeholder="输入消息" />
<button id="send">发送</button> <button id="close">关闭聊天</button>
</body>
说明:
(1)有新的聊天信息会创建新的dom,放入id为"chat-window"的div里,之所以外面还要包裹一个"box"是考虑消息条数过多时,要生成滚动条的效果,所以"box”div设置了固定高度和overflow-y: scroll样式;
(2)聊天效果区分了对方和自己发的消息,模仿一般聊天效果,自己信息会显示右侧,故类名为right-message,对方消息的div标签则类名是left-message,设置弹性盒子,并给自身设置align-self样式来实现左右效果。
页面效果:
2、JS代码
<script>
const ws = new WebSocket('ws://localhost:8080')
const sendBtn = document.getElementById('send')
const closeBtn = document.getElementById('close')
const messageInput = document.getElementById('message')
const chatWindow = document.getElementById('chat-window')
const box = document.getElementById('box')
ws.onopen = function (event) {
console.log('连接成功')
})
// 点击发送按钮时,在点击事件里使用ws.send()传我的消息给服务器
sendBtn.onclick = function (event) {
const message = messageInput.value
ws.send(message)
messageInput.value = ''
chatWindow.innerHTML += `<div class="right-message"><span>我</span><div>${message}</div></div>`
box.scrollTop = box.scrollHeight
}
// 给ws绑定message事件,当服务器接收对方发送的消息并传给我时会触发,event.data就是对方的消息内容
ws.onmessage = function (event) {
const message = event.data
chatWindow.innerHTML += `<div class="left-message"><span>对方</span><div>${message}</div></div>`
box.scrollTop = box.scrollHeight
}
// 点击关闭聊天,将中断连接,我再发送信息,对方将不能收到
closeBtn.onclick = function () {
ws.close()
}
</script>
说明:
(1)首先通过new WebSocket(服务器地址) 进行WebSocket连接,然后创建ws.onopen事件函数,在函数里验证是否连接成功;
(2)给发送按钮添加点击事件,事件函数里要获取发送的消息值,然后ws.send()方法把消息传递给服务器,同时创建dom插入页面,展示我发送的消息;
(3)给ws绑定message事件,这样我就能实时接收对方发送给服务器,服务器再传递给我的消息,获取消息信息,创建dom插入页面当中;
(4)给关闭聊天按钮添加了点击事件,点击关闭将中断该用户的WebSocket连接。
后端Node.js代码
const WebSocket = require('ws')
const server = new WebSocket.Server({ port: 8080 })
let users = new Set()
// 创建连接事件函数
server.on('connection', (ws) => {
users.add(ws)
// 创建接收客户端消息的事件函数
ws.on('message', (message) => {
// 此时消息message为二进制格式,需要转成字符串
message = message.toString()
users.forEach(function (user) {
if (user !== ws) {
user.send(message)
}
})
})
ws.on('close', () => {
users.delete(ws)
})
})
该后端代码和上面的建议案例基本一致,故不再说明。
网页效果展示
启动WebSocket服务器后,打开两个客户端窗口,分别输入文字,实现实时沟通效果。
关闭实时聊天后,终止连接,再次发送信息,对方无法收到效果。
总结
WebSocket技术是一种能够实现全双工通信的协议,它使得客户端和服务器能够建立持久性连接并实现实时的数据传输和交互,从而成为了实现即时通讯的一种重要手段。本文简要介绍了WebSocket技术的基本概念和简单实现,但要想更好地应用该技术,需要进行更多的配置和学习。如果大家对WebSocket技术感兴趣,可以再做进一步的深入研究和学习。
相关推荐
- perl基础——循环控制_principle循环
-
在编程中,我们往往需要进行不同情况的判断,选择,重复操作。这些时候我们需要对简单语句来添加循环控制变量或者命令。if/unless我们需要在满足特定条件下再执行的语句,可以通过if/unle...
- CHAPTER 2 The Antechamber of M de Treville 第二章 特雷维尔先生的前厅
-
CHAPTER1TheThreePresentsofD'ArtagnantheElderCHAPTER2TheAntechamber...
- CHAPTER 5 The King'S Musketeers and the Cardinal'S Guards 第五章 国王的火枪手和红衣主教的卫士
-
CHAPTER3TheAudienceCHAPTER5TheKing'SMusketeersandtheCardinal'SGuard...
- CHAPTER 3 The Audience 第三章 接见
-
CHAPTER3TheAudienceCHAPTER3TheAudience第三章接见M.DeTrévillewasatt...
- 别搞印象流!数据说明谁才是外线防守第一人!
-
来源:Reddit译者:@assholeeric编辑:伯伦WhoarethebestperimeterdefendersintheNBA?Here'sagraphofStea...
- V-Day commemorations prove anti-China claims hollow
-
People'sLiberationArmyhonorguardstakepartinthemilitaryparademarkingthe80thanniversary...
- EasyPoi使用_easypoi api
-
EasyPoi的主要特点:1.设计精巧,使用简单2.接口丰富,扩展简单3.默认值多,writelessdomore4.springmvc支持,web导出可以简单明了使用1.easypoi...
- 关于Oracle数据库12c 新特性总结_oracle数据库12514
-
概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...
- 【开发者成长】JAVA 线上故障排查完整套路!
-
线上故障主要会包括CPU、磁盘、内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍。同时例如jstack、jmap等工具也是不囿于一个方面的问题...
- 使用 Python 向多个地址发送电子邮件
-
在本文中,我们将演示如何使用Python编程语言向使用不同电子邮件地址的不同收件人发送电子邮件。具体来说,我们将向许多不同的人发送电子邮件。使用Python向多个地址发送电子邮件Python...
- 提高工作效率的--Linux常用命令,能够决解95%以上的问题
-
点击上方关注,第一时间接受干货转发,点赞,收藏,不如一次关注评论区第一条注意查看回复:Linux命令获取linux常用命令大全pdf+Linux命令行大全pdf为什么要学习Linux命令?1、因为Li...
- linux常用系统命令_linux操作系统常用命令
-
系统信息arch显示机器的处理器架构dmidecode-q显示硬件系统部件-(SMBIOS/DMI)hdparm-i/dev/hda罗列一个磁盘的架构特性hdparm-tT/dev/s...
- 小白入门必知必会-PostgreSQL-15.2源码编译安装
-
一PostgreSQL编译安装1.1下载源码包在PostgreSQL官方主页https://www.postgresql.org/ftp/source/下载区选择所需格式的源码包下载。cd/we...
- Linux操作系统之常用命令_linux系统常用命令详解
-
Linux操作系统一、常用命令1.系统(1)系统信息arch显示机器的处理器架构uname-m显示机器的处理器架构uname-r显示正在使用的内核版本dmidecode-q显示硬件系...
- linux网络命名空间简介_linux 网络相关命令
-
此篇会以例子的方式介绍下linux网络命名空间。此例中会创建两个networknamespace:nsa、nsb,一个网桥bridge0,nsa、nsb中添加网络设备veth,网络设备间...
- 一周热门
- 最近发表
-
- perl基础——循环控制_principle循环
- CHAPTER 2 The Antechamber of M de Treville 第二章 特雷维尔先生的前厅
- CHAPTER 5 The King'S Musketeers and the Cardinal'S Guards 第五章 国王的火枪手和红衣主教的卫士
- CHAPTER 3 The Audience 第三章 接见
- 别搞印象流!数据说明谁才是外线防守第一人!
- V-Day commemorations prove anti-China claims hollow
- EasyPoi使用_easypoi api
- 关于Oracle数据库12c 新特性总结_oracle数据库12514
- 【开发者成长】JAVA 线上故障排查完整套路!
- 使用 Python 向多个地址发送电子邮件
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- HTML button formtarget 属性 (30)
- opacity 属性 (32)
- transition 属性 (33)