Tomcat中的WebSocket是如何实现的?

Tomcat中的WebSocket是如何实现的?

WebSocket是一种在客户端和服务器之间提供长期、双向、实时通信的协议

全双工通信:WebSocket允许数据同时在客户端和服务器双向通信,无需像HTTP等待请求和响应的循环

单个TCP连接:建立一次连接后,双方可在持久连接上交换任意数量的数据包,减少网络延迟、资源消耗

升级协议:WebSocket连接初始化时,通过HTTP协议进行一次握手,之后便升级到WebSocket协议进行数据传输

事件驱动:WebSocket通信基于事件,如 OnOpenOnMessageOnClose

WebSocket快速入门

SrpingBoot项目整合WebSocket

导入maven依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-WebSocket</artifactId><version>3.0.4</version>
</dependency>

新建一个配置类 @Configuration,将 ServerEndpointExporter 加入容器

@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

新建一个类,使用注解@ServerEndpoint标识路径,并使用注解@Component加入容器

有一系列@OnXX的注解可以标识在方法上,表示当遇到XX情况时调用对应的方法

@OnOpen 建立连接、@OnClose 关闭连接、@OnMessage 收到消息、@OnError 出现错误

@ServerEndpoint("/ws/{id}")
@Component
public class WebSocketServer {private static final Map<Long, Session> map = new ConcurrentHashMap<>();@OnOpenpublic void open(@PathParam("id") Long id, Session session) {map.put(id, session);System.out.println(id + " 建立连接");}@OnClosepublic void close(@PathParam("id") Long id) {map.remove(id);System.out.println(id + " 关闭连接");}@OnMessagepublic void msg(String msg, Session session) {session.getAsyncRemote().sendText("收到消息:" + msg);}@OnErrorpublic void error(String error) {System.out.println(error);}}

注意:open、msg方法中的入参Session是WebSocket中的,而不是servlet规范的

配置的端口为8080,context path为/caicai

server:port: 8080servlet:context-path: /caicai

接下来就可以开始测试了,使用ApiFox工具建立WebSocket连接,发送消息111,最终会调用msg方法发送:收到消息:111

WebSocket原理

我们在配置类中将ServerEndpointExporter类加入容器

@Bean
public ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();
}

ServerEndpointExporter实现SmartInitializingSingleton接口,在容器初始化完Bean后,调用afterSingletonsInstantiated方法

@Override
public void afterSingletonsInstantiated() {registerEndpoints();
}

也就是单例Bean实例化之后执行,会扫描容器中的WebSocket处理类并注册

protected void registerEndpoints() {//收集WebSocket处理类Set<Class<?>> endpointClasses = new LinkedHashSet<>();if (this.annotatedEndpointClasses != null) {endpointClasses.addAll(this.annotatedEndpointClasses);}ApplicationContext context = getApplicationContext();if (context != null) {//从容器中找到@ServerEndpoint注解标识的WebSocket处理类String[] endpointBeanNames = context.getBeanNamesForAnnotation(ServerEndpoint.class);for (String beanName : endpointBeanNames) {endpointClasses.add(context.getType(beanName));}}//注册for (Class<?> endpointClass : endpointClasses) {registerEndpoint(endpointClass);}if (context != null) {Map<String, ServerEndpointConfig> endpointConfigMap = context.getBeansOfType(ServerEndpointConfig.class);for (ServerEndpointConfig endpointConfig : endpointConfigMap.values()) {registerEndpoint(endpointConfig);}}
}

最终加入WebSocketContainer容器(ServerContainer extends WebSocketContainer)

private void registerEndpoint(Class<?> endpointClass) {ServerContainer serverContainer = getServerContainer();Assert.state(serverContainer != null,"No ServerContainer set. Most likely the server's own WebSocket ServletContainerInitializer " +"has not run yet. Was the Spring ApplicationContext refreshed through a " +"org.springframework.web.context.ContextLoaderListener, " +"i.e. after the ServletContext has been fully initialized?");try {if (logger.isDebugEnabled()) {logger.debug("Registering @ServerEndpoint class: " + endpointClass);}//加入容器 serverContainer.addEndpoint(endpointClass);}catch (DeploymentException ex) {throw new IllegalStateException("Failed to register @ServerEndpoint class: " + endpointClass, ex);}
}

ServerEndpointExporter在容器启用时,扫描容器中被@ServerEndpoint标识的WebSocket处理类并注册

在前文曾说过:请求由EndPoint进行网络通信,当处理完网络通信封装成SocketProcessorBase交给线程池进行执行,会先调用Http11Processor解析再调用Adapter适配器交给容器处理

作为升级协议的WebSocket前面网络通信流程不变,而调用Processor时会使用UpgradeProcessorInternal

UpgradeProcessorInternal最终会找到WebSocketContainer容器中对应的WebSocket处理类对应的方法进行调用(不会打到Container容器)

总结

WebSocket是一种长期、双向、实时通信的协议,基于HTTP协议后升级为WebSocket协议

Tomcat在处理WebSocket时与HTTP请求有所不同,处理网络通信依旧还是使用EndPoint

当请求为HTTP时会使用Http11Processor接卸请求,经过适配器最终交给Container容器处理;当请求为WebSocket时使用UpgradeProcessorInternal,路由到WebSocketContainer容器中的ServerEndPoint处理类进行处理

ServerEndpointExporter实现SmartInitializingSingleton接口,在bean实例化后找到容器中被注解ServerEndPoint标识的处理类加入WebSocketContainer容器

🌠最后(不要白嫖,一键三连求求拉~)

本篇文章被收入专栏 Tomcat全解析:架构设计与核心组件实现,感兴趣的同学可以持续关注喔

本篇文章笔记以及案例被收入 Gitee-CaiCaiJava、 Github-CaiCaiJava,除此之外还有更多Java进阶相关知识,感兴趣的同学可以starred持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多技术干货,公众号:菜菜的后端私房菜

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3269081.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第287题寻找重复数

题目&#xff1a; 题解&#xff1a; func findDuplicate(nums []int) int {slow, fast : 0, 0for slow, fast nums[slow], nums[nums[fast]]; slow ! fast; slow, fast nums[slow], nums[nums[fast]] { }slow 0for slow ! fast {slow nums[slow]fast nums[fast]}return s…

【漏洞复现】Jenkins CLI 接口任意文件读取漏洞(CVE-2024-23897)

漏洞简介 Jenkins是一款基于JAVA开发的开源自动化服务器。 Jenkins使用args4j来解析命令行输入&#xff0c;并支持通过HTTP、WebSocket等协议远程传入命令行参数。在args4j中&#xff0c;用户可以通过字符来加载任意文件&#xff0c;这导致攻击者可以通过该特性来读取服务器上…

物联网主机 E6000:智慧应急领域的创新力量

在当今瞬息万变的世界中&#xff0c;突发事件和紧急情况时有发生。如何迅速、准确地应对这些挑战&#xff0c;保障人民生命财产安全&#xff0c;成为了社会发展的重要课题。而物联网主机 E6000 的出现&#xff0c;为智慧应急领域带来了全新的解决方案。 一、强大的性能与功能 物…

好用的缺陷(BUG)跟踪管理系统有哪些?

以下是一些常用的缺陷&#xff08;BUG&#xff09;跟踪管理系统&#xff0c;并对它们进行详细列出和比较&#xff0c;同时讨论哪些系统与LabVIEW兼容或常用于LabVIEW项目中。 1. Jira 功能 强大的问题跟踪和项目管理功能。丰富的自定义选项和插件支持。适用于敏捷开发的看板和…

第七章:贝叶斯分类器

目录 7.1 贝叶斯决策论 7.2 极大似然估计 7.3 朴素贝叶斯分类器 7.4 半朴素贝叶斯分类器 7.5 贝叶斯网 7.5.1 结构 7.5.2 学习 7.5.3 推断 7.6 EM算法 7.1 贝叶斯决策论 概率框架下实施决策的基本理论 给定N个类别&#xff0c;令代表将第j类样本误分类为第i类所产生的…

BFS实现迷宫最短路径

结合队列的知识利用 广度优先遍历&#xff0c;通过对能走的路径的记录以及对走过路径的标记&#xff0c;进行多条路搜查 一、理论基础 如下图的迷宫&#xff1a; 选取所走方向&#xff08;针对某一个位置&#xff09;下&#xff0c;右&#xff0c;上&#xff0c;左&#xff0…

如何进行小程序的调试

Errno错误码 在使用部分小程序 API / 组件时&#xff0c;抛出的异常&#xff08;fail 回调 / Promise reject&#xff09;Error 对象中除了带有 errMsg&#xff0c;还会带有通用错误码 errno。 代码示例 wx.openBluetoothAdapter({success (res) {console.log(res)}fail (er…

测试工作中常听到的名词解释 : )

背景 很多名称其实看字面意思都挺抽象的&#xff0c;有时看群里的测试大佬在不停蹦这类术语&#xff0c;感觉很高大上&#xff0c;但其实很多你应该是知道的&#xff0c;只不过没想到别人是这样叫它的。又或者你的主编程语言不是 Java&#xff0c;所以看不懂他们在讲啥&#x…

微服务安全——OAuth2.1详解、授权码模式、SpringAuthorizationServer实战、SSO单点登录、Gateway整合OAuth2

文章目录 Spring Authorization Server介绍OAuth2.0协议介绍角色OAuth2.0协议的运行流程应用场景授权模式详解客户端模式密码模式授权码模式简化模式token刷新模式 OAuth 2.1 协议介绍授权码模式PKCE扩展设备授权码模式拓展授权模式 OpenID Connect 1.0协议Spring Authorizatio…

Spring Boot:图书管理系统(一)

1.编写用户登录接口 代码&#xff1a; package com.example.demo;import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotatio…

基环树简介

【基环树简介】 ● 众所周知&#xff0c;树上没有环。一棵树由 n 个结点及 n−1 条边构成。 ● 基环树是由 n 个结点及 n 条边组成的连通图。 显然&#xff0c;基环树上存在环。因此&#xff0c;基环树本质上不是树&#xff0c;而是图。基环树又称章鱼图。 基环树的的特别之处就…

qtscrcpy 环境搭建 基于qt5.14.2 vs2017

下载软件 qt5.14.2Visual Studio 2017 Community 安装文件链接参考文末 安装说明 Visual Studio 2017 Community&#xff0c; 一键安装&#xff0c;只需要 c 模块即可 qt5.14.2 安装需要选择msvc 2017 32bit, 因为 ffmpeg 编译的是 32bit 代码下载 https://gitee.com/…

1.ESP32-CAM 下使用 ESP-IDF 打开摄像头

主要资料&#xff1a; 乐鑫官方编程指南 ESP-IDF 编程指南安信可官方模块页 安信可-ESP32-CAM摄像头开发板官方使用教程 安信可ESP32-CAM摄像头开发demo–局域网拍照、实时视频、人脸识别 &#xff08;开发环境是Linux&#xff09; 本文目标是在 Windows 下跑通摄像头 hello …

大数据-52 Kafka 基础概念和基本架构 核心API介绍 应用场景等

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

苍穹外卖01

0. 配置maven (仅一次的操作 1.项目导入idea 2. 保证nginx服务器运行 &#xff08;nginx.exe要在非中文的目录下&#xff09; 开启服务&#xff1a; start nginx 查看任务进程是否存在&#xff1a; tasklist /fi "imagename eq nginx.exe" 关闭ngi…

【优秀python web系统毕设】基于python的全国招聘数据分析可视化系统,包括随机森林算法

1.1 研究背景 自1997年互联网开始在国内的招聘行业发展至今已有二十几年的历史&#xff0c;互联网招聘进入了蓬勃发展的“黄金时代”。根据智研咨询发布的《2023年中国互联网招聘行业发展现状》报告显示&#xff0c;截至2023年5月&#xff0c;中国互联网招聘平台中&#xff0c…

Navicat 17 新特性 | Navicat BI 功能革新升级,助力企业深度挖掘数据潜能

随着 Navicat 17 的发布&#xff0c;在业界引起了广泛的共鸣与热议。我们曾深入剖析其众多革新特性&#xff0c;包括模型设计创新与优化、高效的查询与配置、用户界面交互体验再升级&#xff0c;原生适配国产平台和操作系统和数据字典提升数据结构清晰度&#xff0c;这些新特性…

MySQL查询优化 limit 100000,10加载很慢该怎么优化

需求&#xff1a;查询19年以后发布的商品 数据库表结构如下&#xff1a; 目前数据量&#xff1a;264751 优化前执行时间&#xff1a;0.790s 优化后执行时间&#xff1a;0.467s select id,no,title,cart_title,cid_name from tb_item where id > (select id from tb_item …

Gitlab以及分支管理

一、概述 Git 是一个分布式版本控制系统&#xff0c;用于跟踪文件的变化&#xff0c;尤其是源代码的变化。它由 Linus Torvalds 于 2005 年开发&#xff0c;旨在帮助管理大型软件项目的开发过程。 二、Git 的功能特性 Git 是关注于文件数据整体的变化&#xff0c;直接会将文件…

【Beyond Compare】Beyond Compare下载、安装与使用详细教程

目录 &#x1f33a;1 概述 &#x1f384;2 Beyond Compare 安装包下载 &#x1f33c;3 安装详细教程 &#x1f342;4 免费注册 &#x1f30d;5 使用详情 &#x1f33a;1 概述 Beyond Compare 是一款强大的文件和文件夹比较工具&#xff0c;广泛应用于软件开发、文档管理和…