Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Tomcat中的WebSocket是如何实现的?

Tomcat中的WebSocket是如何实现的?

原创
作者头像
菜菜的后端私房菜
发布于 2024-08-12 01:41:27
发布于 2024-08-12 01:41:27
4130
举报

Tomcat中的WebSocket是如何实现的?

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

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

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

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

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

WebSocket快速入门

SrpingBoot项目整合WebSocket

导入maven依赖

代码语言:xml
AI代码解释
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-WebSocket</artifactId>
    <version>3.0.4</version>
</dependency>

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

代码语言:java
AI代码解释
复制
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

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

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

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

代码语言:java
AI代码解释
复制
@ServerEndpoint("/ws/{id}")
@Component
public class WebSocketServer {

    private static final Map<Long, Session> map = new ConcurrentHashMap<>();

    @OnOpen
    public void open(@PathParam("id") Long id, Session session) {
        map.put(id, session);
        System.out.println(id + " 建立连接");
    }

    @OnClose
    public void close(@PathParam("id") Long id) {
        map.remove(id);
        System.out.println(id + " 关闭连接");
    }

    @OnMessage
    public void msg(String msg, Session session) {
        session.getAsyncRemote().sendText("收到消息:" + msg);
    }

    @OnError
    public void error(String error) {
        System.out.println(error);
    }

}

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

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

代码语言:yaml
AI代码解释
复制
server:
  port: 8080
  servlet:
    context-path: /caicai

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

image.png
image.png

WebSocket原理

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

代码语言:java
AI代码解释
复制
@Bean
public ServerEndpointExporter serverEndpointExporter() {
    return new ServerEndpointExporter();
}

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

代码语言:java
AI代码解释
复制
@Override
public void afterSingletonsInstantiated() {
    registerEndpoints();
}

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

代码语言:java
AI代码解释
复制
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)

代码语言:java
AI代码解释
复制
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适配器交给容器处理

image.png
image.png

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

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

image.png
image.png

总结

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

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

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

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

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

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

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

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

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
SpringBoot整合WebSocket打造在线聊天室实战!!!
1、WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
用户5224393
2019/08/13
2.5K0
SpringBoot整合WebSocket打造在线聊天室实战!!!
SpringBoot 使用WebSocket打造在线聊天室(基于注解)
例如:webSocket.onmessage = function (event) {console.log('WebSocket收到消息:' + event.data);
好好学java
2018/10/18
2.7K0
Springboot整合WebSocket(纯后端)
Java微观世界
2025/01/21
1K0
Springboot整合WebSocket(纯后端)
SpringBoot集成WebSocket,实现后台向前端推送信息
在一次项目开发中,使用到了Netty网络应用框架,以及MQTT进行消息数据的收发,这其中需要后台来将获取到的消息主动推送给前端,于是就使用到了MQTT,特此记录一下。
JAVA葵花宝典
2021/01/03
9940
SpringBoot集成WebSocket,实现后台向前端推送信息
从零玩转Websocket实时通讯服务之前后端分离版本
前言 公司项目需要用到消息提示,那么WebSocket它来了经过我面向百度的学习,废话不多说直接开干. 后端搭建 一、依赖导入 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> 二、搭建websocket服务 1.WebSocke
杨不易呀
2022/01/19
1.2K0
SpringBoot集成WebSocket的基本实现
此时我们第一反应,前端定时使用HTTP协议调用后端接口,刷新界面。OK,需求实现,下班回家!
用户10714507
2023/10/08
1.1K0
Spring Boot 集成 WebSocket,轻松实现信息推送!
在一次项目开发中,使用到了Netty 网络应用框架,以及 MQTT 进行消息数据的收发,这其中需要后台来将获取到的消息主动推送给前端,于是就使用到了MQTT,特此记录一下。
Java技术栈
2021/04/21
1.2K0
SpringBoot整合WebSocket
WebSocket是一种网络通信协议。和HTTP协议一样,都是基于TCP协议来传输数据。
全栈开发日记
2022/05/13
5680
WebSocket
HTTP:HTTP是应用层协议(在传输层使用 TCP,在网络层使用 IP 协议),是一种无状态(即每个请求都是一个新的请求)、无连接(每次连接只处理一个请求)协议,但是HTTP仍然可以借助Cookie(客户端数据储存)和Session(服务端数据储存)实现长连接(HTTP的长连接需要在请求头中加入Connection:keep-alive )。整个通信过程,客户端(浏览器)向服务端发送请求,服务端接收请求并返回响应信息。
十玖八柒
2022/08/01
1.6K0
WebSocket
WebSocket实现在线聊天
“ 这一篇文章前面部分我们会先介绍WebSocket协议的基本知识,在最后我们会用Spring Boot来集成WebSocket实现一个简单的在线聊天功能,我们也可以跨过前面的介绍直接看集成部分,后续在慢慢研究WebSocket。”
每天学Java
2020/06/02
4.2K5
服务端常用的WebSocket框架
输入命令 需要修改的 url、groupId、artifactId、version
码客说
2021/01/20
1.4K0
基于WebSocket实现一个简易的群聊功能
@ServerEndpoint:作用是用来表明当前类是一个节点类,当连接成功之后,用户的操作都会回调这个类对应的对象的方法,对象怎么创建的是根据configurator 属性对应的类来实现的,默认是每个连接对应的对象都是通过反射构建的,但是对于本群聊功能来说,是通过SpringBasedConfigurator对象来获取,这个类的作用接下来会剖析。
三友的java日记
2022/07/27
7850
基于WebSocket实现一个简易的群聊功能
一起来学SpringBoot | 第二十五篇:打造属于你的聊天室(WebSocket)
WebSocket 是 HTML5 新增的一种在单个 TCP 连接上进行全双工通讯的协议,与 HTTP 协议没有太大关系....
battcn
2018/08/03
1.4K1
一起来学SpringBoot | 第二十五篇:打造属于你的聊天室(WebSocket)
传统@ServerEndpoint方式开发WebSocket应用和SpringBoot构建WebSocket应用程序
通过websocket的两种使用方式,让你更加深入理解用法。很多人不懂websocket怎么辨别是谁发送过来的,文中说到实现WebSocketConfigurer接口,定义拦截器可以绑定用户信息,还有其他很多,细细品,对比看比较好!
java思维导图
2020/05/20
9.5K0
WebSocket了解一下
这两天在调试一个WebSocket的接口,折腾了一天的时间终于弄好了。现在对WebSocket的相关知识点做一个记录。主要从如下几个方面进行介绍。
码农飞哥
2021/08/18
6160
SpringBoot2整合WebSocket,实现后台向前端推送信息
WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
Li_XiaoJin
2022/06/12
2.9K0
SpringBoot2整合WebSocket,实现后台向前端推送信息
性能工具之Jmeter压测WebSocket接口(一)
WebSocket是web客户端和服务器之间新的通讯方式,依然架构在HTTP协议之上。使用WebSocket连接,web应用程序可以执行实时的交互,而不是以前的poll方式。
高楼Zee
2019/07/17
3.9K0
性能工具之Jmeter压测WebSocket接口(一)
三分钟构建高性能 WebSocket 服务 | 超优雅的 SpringBoot 整合 Netty 方案
这是个开源的框架。通过它,我们可以像spring-boot-starter-websocket一样使用注解进行开发,只需关注需要的事件(如OnMessage)。并且底层是使用Netty,当需要调参的时候只需要修改配置参数即可,无需过多的关心handler的设置。
芋道源码
2018/12/11
4.8K1
springboot整合websocket
我们都知道HTPP协议是基于请求响应模式,并且无状态的。HTTP通信只能由客户端发起,HTTP 协议做不到服务器主动向客户端推送信息。
全栈程序员站长
2022/09/19
9580
springboot整合websocket
java之WebSocket之ServerEndPoint
The javax.websocket.server package contains annotations, classes,and interfaces to create and configure server endpoints.
IT工作者
2022/05/17
2.5K0
推荐阅读
相关推荐
SpringBoot整合WebSocket打造在线聊天室实战!!!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档