当前位置: 首页 > news >正文

Tomcat Websocket应用实例研究

概述

本文介绍了如何根据Tomcat给出的websocket实例,通过对实例的学习,定制自己基于websocket的应用。

环境及版本:

  1. Ubuntu 22.04.4 LTS
  2. Apache Tomcat/10.1.20
  3. openjdk 11.0.23 2024-04-16
  4. 浏览器:Chrome

相关资源及链接

Class Loader How-To:

Apache Tomcat 11 (11.0.0-M20) - Class Loader How-To

推荐几篇本站内介绍Websocket原理及tomcat附带的实例的文章,可作为参考:

Websocket原理-CSDN博客

看完让你彻底理解 WebSocket 原理_websocket原理-CSDN博客

Tomcat实现Web Socket_tomcat 9 wss服务配置-CSDN博客

Tomcat提供的websocket实例

Tomcat安装完成后给出的Examples中,包括了有关websocket的例子。

如上图,点击‘Examples’,进入如下界面:

继续点击‘WebSocket Examples’,进入如下界面:

点击‘Echo example’,进入如下界面:

从界面可以看出,Tomcat提供以下三种方式与服务器建立websocket双向通信:

  1. programmatic API
  2. annotation API (basic)
  3. annotation API (stream)

programmatic:编程式,即编写一个Java类继承javax.websocket.Endpoint(根据tomcat及openjdk的版本不同,或继承jakarta.websocket.Endpoint,本文中为jakarta),并实现它的onOpen、onClose和onError等方法。

annotation:注解式,实现一个业务类并给其添加websocket相关的注解(通过@ServerEndpoint(...)),注解表明当前业务类是已经实现了WebSocket规范的Endpoint。根据上面tomcat给出的实例界面显示,注解式又分为basic和stream两种模式。

本文不对上述三种方式展开详细讨论。

点击上面(tomcat)界面的三种websocket的实现方式,下方的编辑框中会同步显示将实际在代码中用到的websocket URL,例如点击‘annotation API (basic)’,下面编辑框的内容同步更新为‘ws://host/examples/websocket/echoAnnotation’,其中host为服务器的URL(含端口),以下均使用‘127.0.0.1:8080’作为默认值,例如:

ws://127.0.0.1:8080/examples/websocket/echoAnnotation

客户端浏览器将使用该URL串作为目标websocket服务器地址。

点击‘Connect’按钮,再点击‘Echo message’按钮,界面如下:

依葫芦画瓢

now,我们照着tomcat给出的实例依葫芦画瓢建立自己的websocket应用,并试图在这一过程中逐步理解tomcat的websocket实现原理以及相关的配置。

新建一个自己的webapp,例如命名为myws:

  1. 在目录‘opt/tomcat/webapps’新建目录‘myws’;
  2. 将examples实例下‘websocket’目录及其文件拷贝到‘myws’目录下;
  3. 在‘myws’目录下新建目录‘WEB-INF’;进入新建的‘WEB-INF’目录,继续创建目录‘classes’,此目录为本文涉及的tomcat 11加载Java类的默认目录!
  4. 将examples实例下的‘WEB-INF/classes/websocket’目录及其文件拷贝到myws应用下新建的‘classes’目录。

依葫芦画瓢(文件拷贝)暂时到此。

在新建的myws应用根目录下新建一个index.html文件,内容如下:

<html lang="zh-CN">

<head>

<meta charset="UTF-8">

<title>项目测试首页列表</title>

<style>

  body {

    background-color: lightblue;

  }

  h1 {

    text-align: center;

  }

  div.exam_list {

    font-family: verdana;

    font-size: 18px;

    margin-left: 100px;

    margin-top:5px;

  }

</style>

</head>

<body>

<h1>tomcat websocket应用学习</h1>

<p>

<div class="exam_list"><li><a href="/myws/websocket/index.xhtml">examples实例学习</a></li></div>

</p>

</body>

</html>

启动浏览器,输入URL,例如:http://hostname/myws,出现如下界面:

点击页面链接,进入如下界面(此界面与之前的完全相同):

点击‘Echo example’,进入如下界面(此界面与之前的完全相同):

分别点击tomcat下websocket的三种通信实现方式,下方编辑框的链接URI为:

  1. ws://127.0.0.1:8080/examples/websocket/echoProgrammatic
  2. ws://127.0.0.1:8080/examples/websocket/echoAnnotation
  3. ws://127.0.0.1:8080/examples/websocket/echoStreamAnnotation

点击页面其他按钮,并操作,一切正常,注意观察三个URL,其仍然连接的是安装包默认提供的examples项目上了,故一切正常

打开并编辑文件‘echo.xhtml’,注意如下代码行:

<div>

    <div id="connect-container">

        <div>

            <span>Connect to service implemented using:</span>

            <br/>

            <!-- echo example using new programmatic API on the server side -->

            <input id="radio1" type="radio" name="group1" value="/examples/websocket/echoProgrammatic"

                   onclick="updateTarget(this.value);"/> <label for="radio1">programmatic API</label>

            <br/>

            <!-- echo example using new annotation API on the server side -->

            <input id="radio2" type="radio" name="group1" value="/examples/websocket/echoAnnotation"

                   onclick="updateTarget(this.value);"/> <label for="radio2">annotation API (basic)</label>

            <br/>

            <!-- echo example using new annotation API on the server side -->

            <input id="radio3" type="radio" name="group1" value="/examples/websocket/echoStreamAnnotation"

                   onclick="updateTarget(this.value);"/> <label for="radio3">annotation API (stream)</label>

            <br/>

            <!-- echo example using new annotation API on the server side -->

            <!-- Disabled by default -->

            <!--

            <input id="radio4" type="radio" name="group1" value="/examples/websocket/echoAsyncAnnotation"

                   οnclick="updateTarget(this.value);"/> <label for="radio4">annotation API (async)</label>

            -->

        </div>

根据代码,如前所述,每当用户点击了不同的通信方式,页面会自动更新websocket连接,其中实例代码还注释掉了第四种方式‘AsynAnntation’。

将上述代码中高亮的‘examples’替换为本项目名称‘myws’。刷新页面,点击选择不同的通信方式,确认编辑框中websocket连接URL更新。

回到页面进行操作,OK!一切正常!!!

温馨提示(重要的问题说三遍),在测试页面之前务必通过tomcat的管理页面重新启动web应用,界面如下:

点击‘停止’按钮,再点击‘启动’按钮。

不知道如何配置管理页面的,可直接重启tomcat服务。

重要的事情说三遍!!!一定记得重启应用!

tomcat三种websocket通信方式测试

一个小测试:

查看目录‘myws/WEB-INF/classes/websocket’,除了四个子目录,注意该目录下有两个文件,一个是‘ExamplesConfig.java’,另一个是对应的class文件。

从项目目录中删除该两个文件,重新启动web应用,再次进入Echo example界面,同样进行三种方式的通信测试,其中后两种(基础注解式/annotation API (basic)和流式注解式/annotation API (stream))正常,第一种‘编程式’连接失败,连接失败界面如下。

查看目录‘myws/WEB-INF/classes/websocket/echo’,该目录下文件列表如下图。

再次回顾前文提到的三种通信方式的URL,如下:

  1. ws://127.0.0.1:8080/examples/websocket/echoProgrammatic
  2. ws://127.0.0.1:8080/examples/websocket/echoAnnotation
  3. ws://127.0.0.1:8080/examples/websocket/echoStreamAnnotation

查看文件EchoAnnotation.java,在类定义之前有一处申明,代码如下:

注解式下,通过‘@ServerEndpoint’添加注解后,在项目(网站)启动时tomcat服务会自动扫描(WEB-INF/calsses目录下)java类,并将注解类与ws服务关联。

查看文件EchoStreamAnnotation.java,同样有一处类似的申明,如下:

在EchoEndpoint.java文件中,没有发现类似的注解。

所以,在删除了文件ExampleConfig(并重新启动应用)后,注解式的方式依然有效,编程式的方式连接失败。

重新拷贝ExampleConfig.java/.class到应用目录,查看ExampleConfig.java,内容如下:

package websocket;

import java.util.HashSet;

import java.util.Set;

import jakarta.websocket.Endpoint;

import jakarta.websocket.server.ServerApplicationConfig;

import jakarta.websocket.server.ServerEndpointConfig;

import websocket.drawboard.DrawboardEndpoint;

import websocket.echo.EchoEndpoint;

public class ExamplesConfig implements ServerApplicationConfig {

    @Override

    public Set<ServerEndpointConfig> getEndpointConfigs(

            Set<Class<? extends Endpoint>> scanned) {

        Set<ServerEndpointConfig> result = new HashSet<>();

        if (scanned.contains(EchoEndpoint.class)) {

            result.add(ServerEndpointConfig.Builder.create(

                    EchoEndpoint.class,

                    "/websocket/echoProgrammatic").build());

        }

        if (scanned.contains(DrawboardEndpoint.class)) {

            result.add(ServerEndpointConfig.Builder.create(

                    DrawboardEndpoint.class,

                    "/websocket/drawboard").build());

        }

        return result;

    }

    @Override

    public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {

        // Deploy all WebSocket endpoints defined by annotations in the examples

        // web application. Filter out all others to avoid issues when running

        // tests on Gump

        Set<Class<?>> results = new HashSet<>();

        for (Class<?> clazz : scanned) {

            if (clazz.getPackage().getName().startsWith("websocket.")) {

                results.add(clazz);

            }

        }

        return results;

    }

}

首先类ExampleConfig继承自ServerApplicationConfig,该类会执行目录自动扫描,对于目录(及子目录)下所有继承自‘Endpoint’的类进行处理,并分别映射了两个ws服务:

  1. "/websocket/echoProgrammatic"
  2. "/websocket/drawboard"

其中第一个正是echo测试中的第一种基于编程式的通信方式所对应的服务,第二个为多人协同画板应用的实例服务(对应的注册名称)。

对于所有注解式实现的websocket服务(类),示例代码中进行了过滤操作,即任何不是以‘websocket.’开头的服务,都将被屏蔽。上面的实际测试中(删除ExamplesConfig),注解式的不需要代码中的add(clazz)操作也可以正常工作。

另外,在自己的应用中,可将配置文件/类(ExamplesConfig)更改为项目对应的名称,例如本例中更改为MywsConfig.java/class,记得类名与文件一致,重新编译.java,并重启web应用。

记录一下ubuntu下成功编译MywsConfig.java的命令(好记性不如烂笔头),主要是指定import的相关库/类的路径,如下:

javac -cp /opt/tomcat/webapps/myws/WEB-INF/classes:/opt/tomcat/lib/* MywsConfig.java

其他

Tomcat有关websocket实现的包在目录$CATALINA_HOME/lib($CATALINA_HOME的默认安装目录为‘/opt/tomcat’)下,包含三个文件,如下图:

本文未涉及注解式以及编程式websocket通信的各接口的分析,相关文章可在站内搜索。

相关文章:

Tomcat Websocket应用实例研究

概述 本文介绍了如何根据Tomcat给出的websocket实例&#xff0c;通过对实例的学习&#xff0c;定制自己基于websocket的应用。 环境及版本&#xff1a; Ubuntu 22.04.4 LTSApache Tomcat/10.1.20openjdk 11.0.23 2024-04-16浏览器&#xff1a;Chrome 相关资源及链接 Class…...

leetcode-11-二叉树前中后序遍历以及层次遍历

一、递归版 前序遍历 &#xff08;先根遍历&#xff09; 中左右 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result new ArrayList<Integer>();preorder(root, result);return result;}public void preorder…...

Python基础学习笔记(十一)——集合

目录 一、集合的介绍与创建二、集合的存储原理三、元素的修改1. 添加元素2. 删除元素 四、集合的运算五、集合的判定 一、集合的介绍与创建 集合&#xff08;set&#xff09;&#xff0c;一种可变、无序、不重复的数据结构&#xff0c;由大括号{}内、用逗号分隔的一组元素组成。…...

FineReport

1.FineReport 官网 &#xff1a;FineReport产品简介- FineReport帮助文档 - 全面的报表使用教程和学习资料 下载地址 免费下载FineReport - FineReport报表官网 FineReport是一款用于报表制作&#xff0c;分析和展示的工具。 普通模板&#xff1a;是 FineReport 最常用&#xf…...

嵌入式就业前景好么

嵌入式就业前景在当前环境下是较为乐观的&#xff0c;以下是对嵌入式就业前景的详细分析&#xff1a; 广泛应用领域&#xff1a;嵌入式系统广泛应用于智能家居、医疗设备、航空航天等领域。随着物联网&#xff08;IoT&#xff09;的快速发展&#xff0c;预计到2024年&#xff…...

为啥找对象千万别找大厂男,还好我不是大厂的。。

网上看到一大厂女员工发文说&#xff1a;找对象千万别找大厂男&#xff0c;理由说了一大堆&#xff0c;无非就是大厂男为了逃避带娃&#xff0c;以加班为由宁愿在工位上玩游戏也不愿回家。当然这种观点有的人赞同有的人反对。 网友精彩评论&#xff1a; --------------下面是今…...

如何查看k8s中service的负载均衡策略

在Kubernetes中&#xff0c;Service的负载均衡策略一般由kube-proxy负责&#xff0c;kube-proxy使用iptables或IPVS规则进行负载均衡。默认情况下&#xff0c;kube-proxy使用的是轮询&#xff08;Round Robin&#xff09;策略&#xff0c;但是在使用IPVS模式时&#xff0c;可以…...

Linux-DNS域名解析服务01

BIND 域名服务基础 1、DNS&#xff08;Domain Name System&#xff09;系统的作用及类型 整个 Internet 大家庭中连接了数以亿计的服务器、个人主机&#xff0c;其中大部分的网站、邮件等服务器都使用了域名形式的地址&#xff0c;如 www.google.com、mail.163.com 等。很显然…...

[c++刷题]贪心算法.N01

题目如上: 首先通过经验分析&#xff0c;要用最少的减半次数&#xff0c;使得数组总和减少至一半以上&#xff0c;那么第一反应就是每次都挑数组中最大的数据去减半&#xff0c;这样可以是每次数组总和值减少程度最大化。 代码思路:利用大根堆去找数据中的最大值&#xff0c;…...

推荐常用的三款源代码防泄密软件

三款源代码防泄密软件——安秉源代码加密、Virbox Protector 和 MapoLicensor——确实各自在源代码保护的不同方面有其专长。这些软件可以满足企业对于源代码保护的三大需求&#xff1a;防止泄露、防止反编译和防止破解。 安秉源代码加密&#xff1a; 专注于源代码文件的加密&…...

Android 13 高通设备热点低功耗模式(2)

前言 之前写过一篇文章:高通热点被IOS设备识别为低数据模式,该功能仿照小米的低数据模式写的,散发的热点可以达到被IOS和小米设备识别为低数据模式。但是发现IOS设备如果后台无任何网络请求的时候,息屏的状态下过一会,会自动断开热点的连接。 分析 抓取设备的热点相关的…...

web前端任职条件:全面解析

web前端任职条件&#xff1a;全面解析 在当今数字化快速发展的时代&#xff0c;Web前端技术已经成为互联网行业不可或缺的一部分。作为一名Web前端开发者&#xff0c;需要具备哪些任职条件呢&#xff1f;本文将从四个方面、五个方面、六个方面和七个方面为您深入剖析。 四个方…...

分析医药零售数据该用哪个BI数据可视化工具?

数据是企业决策的重要依据&#xff0c;可以用于现代企业大数据可视化分析的BI工具有很多&#xff0c;各有各擅长的领域。那么哪个BI数据可视化工具分析医药零售数据又好又快&#xff1f; 做医药零售数据分析首推奥威BI数据可视化工具&#xff01; 奥威BI数据可视化工具做医药…...

如何使用芯片手册做软件开发?

在阅读和利用芯片手册进行软件开发时&#xff0c;你应该关注以下几个关键点&#xff1a; 引脚功能&#xff1a;了解芯片上每个引脚的功能&#xff0c;包括它们可以被配置为输入还是输出&#xff0c;以及它们支持的特殊功能&#xff0c;如模拟输入、PWM输出、中断等。 寄存器映…...

基于深度学习的文本翻译

基于深度学习的文本翻译 基于深度学习的文本翻译&#xff0c;通常称为神经机器翻译&#xff08;Neural Machine Translation, NMT&#xff09;&#xff0c;是近年来在自然语言处理&#xff08;NLP&#xff09;领域取得显著进展的技术。NMT通过使用深度神经网络来自动学习和翻译…...

Unity制作透明材质直接方法——6.15山大软院项目实训

之前没有在unity里面接触过材质的问题&#xff0c;一般都是在maya或这是其他建模软件里面直接得到编辑好材质的模型&#xff0c;然后将他导入Unity里面&#xff0c;然后现在碰到了需要自己在Unity制作透明材质的情况&#xff0c;所以先搜索了一下有没有现成的方法&#xff0c;很…...

【HarmonyOS NEXT】如何通过h5拉起应用(在华为浏览器中拉起应用)

华为浏览器支持拉起外部应用 浏览器访问网页经常会遇到deeplink的场景。当前处理方案统一为使用AMS系统能力startAbility去隐式拉起。传递的want参数为 { "actions": "ohos.want.action.viewData", "uri": deeplink链接 } 网页需要给自己的应用拉…...

模板方法模式(大话设计模式)C/C++版本

模板方法模式 C #include <iostream> using namespace std;class TestPaper { public:void TestQ1(){cout << "杨过得到&#xff0c;后来给了郭靖&#xff0c;炼成倚天剑&#xff0c;屠龙刀的玄铁可能是[ ]\na.球磨铸铁 b.马口贴 c.高速合金钢 d.碳素纤维&qu…...

数据提取:数据治理过程中的质量保障

一、引言 在数字化时代&#xff0c;数据已经成为企业决策和运营的核心资源。然而&#xff0c;数据的价值并不仅仅在于其数量&#xff0c;更在于其质量。数据治理作为确保数据质量、安全性和一致性的重要手段&#xff0c;对于企业的长期发展至关重要。其中&#xff0c;数据提取…...

第55期|GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...

React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构

React 实战项目&#xff1a;微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇&#xff01;在前 29 篇文章中&#xff0c;我们从 React 的基础概念逐步深入到高级技巧&#xff0c;涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...

Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解

文章目录 一、开启慢查询日志&#xff0c;定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...