WebSocker

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: WebSocker

WebSocket

概述

相比 HTTP 协议来说,WebSocket 协议对大多数后端开发者是比较陌生的。相比来说, WebSocket 协议重点是提供了服务端主动向客户端发送数据的能力,这样我们就可以完成实时性较高的需求。例如:聊天IM即时通讯功能,消息订阅服务、网页游戏等

这里有个误区,WebSocket相比普通的Socket来说,仅仅是借助HTTP协议完成握手,创建连接。后续所有的通讯都和HTTP协议无关。

理清 WebSocket 和 HTTP 的关系

总结:

  1. WebSocket 和 HTPP 都是基于TCP协议的两个不同的协议
  2. WebSocket 依赖于HTTP连接

WebSocket 依赖于 HTTP 连接,那么它如何从链接的 HTTP 协议转化为 WebSocket 协议?

每个 WebSocket 链接都始于 HTTP 请求。具体来说, WebSocket 协议第一次握手连接时,通过 HTTP 协议在传送 WebSocket 支持的版本号、协议的子版本号、原始地址、主机地址等等一系列字段给服务端:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Version: 13

注意:关键的地方是,这里面有个Upgrade首部,用来把当前的HTTP请求升级到 WebSocket 协议,这是 HTTP 协议本身的内容,是为了扩展其他的通讯协议。如果服务器支持新的协议,则必须返回 101

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

至此,HTTP请求物尽其用,如果成功出发onopen事件,否则触发onerror事件,后面的传输则不再依赖HTTP协议。

WebSocket 为什么要依赖 HTTP 协议的连接 ?

  • WebSocket 设计上就是天生为 HTTP 增强通讯,所以在 HTTP 协议链接的基础上是自然的一件事,并因此能获得 HTTP 的诸多便利。
  • 诸多便利中有一条很重要,基于 HTTP 连接将获取最大的一个兼容支持,比如即使服务器不支持 WebSocket 也能建立 HTTP 通信,只不过返回的是 onerror 而已,这显然比服务器无响应要好得多。

在实现提供 WebSocket 服务的项目中,一般有如下几种解决方案:

如果仅仅是仅仅提供 WebSocket 协议的支持,可以考虑采用方案一或者方案二。在使用上,两个方案是比较接近的。相比来说,方案一 Spring WebSocket 内置了对 STOMP 协议的支持。

WebSocket Demo

C:\Users\Administrator\Desktop\mall\spring-websocket-demo
C:\Users\Administrator\Desktop\mall\Tomcat-websocket-demo
http://www.iocoder.cn/Spring-Boot/WebSocket/

如何保证消息一定送达给用户呢?

如果用户不在线的时候,消息持久化到MySQL、MongoDB、Redis等等数据库中,这个是必要的。

我们在考虑下边界情况,客户端网络环境差,特别是在移动端场景下,出现网络闪断,可能会出现连接实际断开,而服务器以为客户端处于在线情况。吃屎,服务端会将消息发送给客户端,那么消息实际就会发送到 “空气”中,产生丢失情况,要解决这种情况的问题,需要引入客户端的 ACK 消息机制。目前主流的做法有两种方法。

第一种基于每一条消息编号 ACK 整体流程如下:

  • 无论客户端是否在线,服务端都先把接收到的消息持久化到数据库中。如果客户端在线,服务端将完整的消息推送给客户端
  • 客户端接收到消息后,发送 ACK 消息编号给服务端,告知已收到该消息。服务端在收到 ACK 消息编号的时,标记该消息已经发送成功。
  • 服务端定时轮询,在线的客户端,是否有超过N秒未 ACK 的消息,如果有,则重新发送消息给客户端。

不过因为服务端仍然需要定时轮询,也会导致服务端压力较大。所以,这种方案基本已经不采用了。

第二种,基于滑动窗口 ACK,整体流程如下:

  • 无论客户端是否在线,服务端都先把接收到的消息持久化到数据库中。 如果客户端此时在线,服务端将消息编号推送给客户端。
  • 客户端在接收到消息编号之后,和本地的消息编号进行对比。如果比本地的小,说明该消息一经收到,忽略不计;如果比本地大,使用本地的消息编号,向服务端拉取大于本地的消息编号的消息列表,增量消息列表。拉去完之后,更新消息列表中最大的消息编号为新的本地的消息编号
  • 服务端在收到客户端拉取增量的消息列表时,将请求的编号记录到数据库中,用于知道客户端此时本地的最新消息编号。
  • 考虑到服务端将消息编号推送给客户端,也会存在丢失的情况,所以客户端会每 N 秒定时向服务端拉取大于本地的消息编号的消息列表。

这种方式,在业务被称为推拉结合的方案,在分布式消息队列、配置中心、注册中心实现实时的数据同步,经常被采用。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
监控 druid Java
监控druid数据库连接池连接泄露的思路
监控druid数据库连接池连接泄露的思路
1038 2
|
5月前
|
消息中间件 安全 druid
GitHub昙花一现!《Spring Boot趣味实战课》神作开源几分钟被下架
今天给大家分享好书了:刘水镜老师的 《Spring Boot趣味实战课》,网上依旧是没有开源版本!小编会在文末附电子版免费下载方式。 刘水镜是谁? 十余年持续技术文章输出,CSDN博客专家。2020年《 Spring Boot趣味私房课》专栏上线,凭借风趣幽默、深入浅出的写作风格深受读者好评。 《Spring Boot趣味实战课》 内容丰富、趣味实战是本书的两大特色 涵盖 Spring MVC、MyBatis Plus、Spring DaJPA、Spring Security、Quartz等主流框架 整合MySQL. Druid、Redis、 RabbitMQ、Elastics
90 0
|
缓存 druid Java
SpringBoot源码 | prepareContext方法解析
本文主要讲述SpringBoot启动流程源码中的prepareContext()方法
SpringBoot源码 | prepareContext方法解析
|
5月前
|
Docker 容器
如何在Docker中设置环境变量?
如何在Docker中设置环境变量?
988 0
|
5月前
|
机器学习/深度学习 自然语言处理 算法
社交网络分析2(下):社交网络情感分析的方法、挑战与前沿技术
社交网络分析2(下):社交网络情感分析的方法、挑战与前沿技术
337 0
|
12月前
|
存储 Kubernetes NoSQL
k8s1.20版本部署Redis集群(三主三从)——2023.05
k8s1.20版本部署Redis集群(三主三从)——2023.05
699 1
|
easyexcel Java 数据库
excel多sheet页的导入
excel多sheet页的导入
392 0
excel多sheet页的导入
|
SQL 存储 数据库连接
SqlServer timestamp
在 SQL Server 中,timestamp 是一种二进制数据类型,用于记录表中行的版本号。当表中的数据发生变化时,SQL Server 会自动更新 timestamp 字段的值,以便记录每个行的版本号。timestamp 字段的值是一个自增的二进制数,长度为 8 字节(64 位),并且与机器硬件和操作系统无关。
276 0
|
关系型数据库 MySQL
|
前端开发
Vue3+ts——动画Loading以及引入本地随机背景效果
动画Loading以及引入本地随机背景效果
424 0