springboot创建websocket服务端
springboot创建websocket服务端
1.配置类
package com.neusoft.airport.websocket;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;import java.text.SimpleDateFormat;
import java.util.Date;/*** @author dume* @create 2023-07-24 17:11**/
@Configuration
//@ConditionalOnWebApplication
public class WebSocketConfig {/*** ServerEndpointExporter 作用** 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint** @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}/*** 通信文本消息和二进制缓存区大小* 避免对接 第三方 报文过大时,Websocket 1009 错误* @return*/@Beanpublic ServletServerContainerFactoryBean createWebSocketContainer() {ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();// 在此处设置bufferSizecontainer.setMaxTextMessageBufferSize(10240000);container.setMaxBinaryMessageBufferSize(10240000);container.setMaxSessionIdleTimeout(15 * 60000L);return container;}}
2.通讯类server
package com.neusoft.airport.websocket;import com.alibaba.fastjson.JSONObject;import com.neusoft.caeid.upms.license.LicenseSetting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** @author dume* @create 2023-07-24 17:11**/@Component
@ServerEndpoint("/webSocket/{sid}")
public class WebSocketServer implements EnvironmentAware {private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();private ScheduledExecutorService executor= Executors.newSingleThreadScheduledExecutor();private static Environment globalEnvironment;//接收sidprivate String sid="";//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;@Autowiredprivate Environment environment;/*** 连接建立成功调用的方法** @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据*/@OnOpenpublic void onOpen(Session session,@PathParam("sid") String sid) throws IOException {//防止重复连接for (WebSocketServer item : webSocketSet) {if (item.sid.equals(sid)) {webSocketSet.remove(item);subOnlineCount(); //在线数减1break;}}this.session = session;this.environment = globalEnvironment;webSocketSet.add(this); //加入set中addOnlineCount(); //在线数加1log.info("有新用户连接,连接名:"+sid+",当前在线人数为" + getOnlineCount());this.session.getAsyncRemote().sendPing(ByteBuffer.wrap(new byte[0]));this.sid=sid;}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this); //从set中删除subOnlineCount(); //在线数减1log.info("连接关闭:"+sid+"当前在线人数为" + getOnlineCount());}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息* @param session 可选的参数*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到来自:"+sid+"的信息:"+message);
// //群发消息for (WebSocketServer item : webSocketSet) {try {LicenseSetting.CheckParams checkParams = LicenseSetting.getCheckParams();//当前license信息log.info("当前证书信息: "+ JSONObject.toJSONString(checkParams));if(null!=checkParams.getLicenseParams()){checkParams.getLicenseParams().setSysMessageInfo(null);}String sendMessageStr = JSONObject.toJSONString(checkParams);if(checkParams.getStatus()==0){log.info("证书验证成功!");}else {log.error("证书验证失败!");}item.sendMessage(sendMessageStr);} catch (IOException e) {log.error("推送消息到:"+sid+",推送内容出错",e);continue;}}}/*** 发生错误时调用*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误",error);}// 接收心跳消息@OnMessagepublic void onPong(PongMessage pong, Session session, @PathParam("sid") String sid) {executor.schedule(() -> {try {// 发送空的Ping消息session.getAsyncRemote().sendPing(ByteBuffer.wrap(new byte[0]));} catch (IOException e) {// 处理发送失败的情况log.error("Ping 用户:{} 心跳异常,关闭会话,错误原因:{}", sid, e.getMessage());onClose();}}, 10, TimeUnit.SECONDS);}/*** 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。*/public void sendMessage(String message) throws IOException {//this.session.getBasicRemote().sendText(message);this.session.getAsyncRemote().sendText(message);}/*** 群发自定义消息* */public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {//log.info("推送消息到窗口"+sid+",推送内容:"+message);for (WebSocketServer item : webSocketSet) {try {log.info("推送消息到:"+item.sid+",推送内容:"+message);//这里可以设定只推送给这个sid的,为null则全部推送if(sid==null||sid.length()==0) {item.sendMessage(message);}else if(item.sid.equals(sid)){item.sendMessage(message);}} catch (IOException e) {log.error("发生错误",e);continue;}}}//推送给指定sidpublic static boolean sendInfoBySid(@PathParam("sid") String sid,String message) throws IOException {//log.info("推送消息到窗口"+sid+",推送内容:"+message);boolean result=false;if(webSocketSet.size()==0){result=false;}for (WebSocketServer item : webSocketSet) {try {if(item.sid.equals(sid)){item.sendMessage(message);log.info("推送消息到:"+sid+",推送内容:"+message);result=true;}} catch (IOException e) {log.error("发生错误",e);continue;}}return result;}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}public static synchronized void subOnlineCount() {if(WebSocketServer.onlineCount>0){WebSocketServer.onlineCount--;}}@Overridepublic void setEnvironment(final Environment environment) {this.environment = environment;if (globalEnvironment == null && environment != null) {globalEnvironment = environment;}}
}
相关文章:
springboot创建websocket服务端
springboot创建websocket服务端 1.配置类 package com.neusoft.airport.websocket;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndp…...

网络安全攻防实战:探索互联网发展史
大家好,我是沐尘而生。 互联网发展史:数字世界的壮阔画卷 从早期的ARPANET到今天的万物互联,互联网经历了漫长的发展过程。然而,随着技术的进步,网络安全问题也随之而来。我们不仅要探索互联网的壮阔历程,…...

pwm接喇叭搞整点报时[keyestudio的8002模块]
虽然现在查看时间很方便,但是其实好像我的时间观念却越来越差。于是决定搞一个整点报时,时常提醒自己时光飞逝,不要老是瞎墨迹。 这篇主要讲一下拼装方式和配置,就差不多了。不涉及什么代码。3针的元器件,去掉正负接线…...
配置listener tcps加密 enable SSL encryption for Oracle SQL*Net
一 配置客户端和服务端的wallet 2端配置方法一致,相互添加证书 orapki wallet create -wallet “/u01/oracle/wallet” -pwd Wdkf984jkkgekj434FKFD -auto_login_local orapki wallet add -wallet “/u01/oracle/wallet” -pwd Wdkf984jkkgekj434FKFD -dn “CNho…...
【Sklearn】基于逻辑回归算法的数据分类预测(Excel可直接替换数据)
【Sklearn】基于逻辑回归算法的数据分类预测(Excel可直接替换数据) 1.模型原理2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果1.模型原理 逻辑回归是一种用于二分类问题的统计学习方法,尽管名字中含有“回归”,但实际上是一种分类算法。它的基本原理是通…...
自然数的拆分问题
题目描述 任何一个大于 11 的自然数 n,总可以拆分成若干个小于 n 的自然数之和。现在给你一个自n,要求你求出 n 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。 输…...

du -mh命令
du 命令查看每个文件夹大小(du 命令用法详解),du 命令的英文全拼是 disk usage,意思是占用的磁盘空间,该命令可以显示目录或文件的大小。 在执行“ du ”命令时,使用“ -h ”参数会以“人类可读格式”显示…...

MySQL 8 group by 报错 this is incompatible with sql_mode=only_full_group_by
文章目录 sql_mode配置ONLY_FULL_GROUP_BYSTRICT_TRANS_TABLESNO_ZERO_IN_DATENO_ZERO_DATEERROR_FOR_DIVISION_BY_ZERONO_AUTO_CREATE_USERNO_ENGINE_SUBSTITUTION 局部修改配置windows修改配置Linux修改配置 sql_mode配置 ONLY_FULL_GROUP_BY 用于控制是否允许对查询结果进…...

Mongodb (四十一)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、概述 1.1 相关概念 1.2 特性 二、应用场景 三、安装 四、目录结构 五、默认数据库 六、 数据库操作 6.1 库操作 6.2 文档操作 七、MongoDB数据库备份 7.1 备…...

16 dlsys GAN
和有监督的分类工作不同,生成任务的目标更不明确。难以评价生成结果的好坏。 Oracle discriminator 假设我们有一个先知判别器oracle discriminator可以分辨我们生成的内容是真还是假。 D(x) 表示判别数据为真的概率。 我们想让生产成的结果足够真实,所…...

css3-flex布局:基础使用 / Flexbox布局
一、理解flex 二、理解Flex布局(又称Flexbox布局) Flex布局(又称Flexbox布局)是一种基于Web的CSS3布局模式,其目的是为了更加灵活和自适应地布置各种各样的网页元素。Flex布局通过将一个父容器分割为一个或多个弹性项…...

MYSQL-习题掌握
文章目录 SQL基本操作1 设计表操作1.1 关系表字段1.2 关系表创建1.3 关系表数据1.4 关系表关系 2 SQL操作2.1 SQL 1-102.2 SQL 11-202.3 SQL 21-302.4 SQL 31-402.5 SQL 41-50 SQL基本操作 1 设计表操作 1.1 关系表字段 1 学生表 student s_ids_names_births_sex学生编号学…...
Python-迭代
1、迭代器 迭代器是一个对象,它可以记录遍历的相关信息,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器有两个基本的方法:iter() 和 next()。我们都过命令行工具,了解一下python的底层迭代…...

【论文阅读】DEPCOMM:用于攻击调查的系统审核日志的图摘要(SP-2022)
Xu Z, Fang P, Liu C, et al. Depcomm: Graph summarization on system audit logs for attack investigation[C]//2022 IEEE Symposium on Security and Privacy (SP). IEEE, 2022: 540-557. 1 摘要 提出了 DEPCOMM,这是一种图摘要方法,通过将大图划…...

大语言模型之一 Attention is all you need ---Transformer
大语言模型已经在很多领域大显身手,其应用包括只能写作、音乐创作、知识问答、聊天、客服、广告文案、论文、新闻、小说创作、润色、会议/文章摘要等等领域。在商业上模型即产品、服务即产品、插件即产品,任何形态的用户可触及的都可以是产品,…...

数字鸿沟,让气候脆弱者更脆弱
随着科技的飞速发展,数字化正在改变我们的生活方式和社会结构。然而,数字鸿沟(Digital Divide)这一长期存在的问题,却在某些方面加剧了社会的不平等现象。在此,我们将探讨数字鸿沟如何加剧了气候脆弱者的脆…...

Tomcat 部署优化
Tomcat Tomcat 开放源代码web应用服务器,是由java代码开发的 tomcat就是处理动态请求和基于java代码的页面开发 可以在html当中写入java代码,tomcat可以解析html页面当中的iava,执行动态请求 动态页面机制有问题:不对tomcat进行优…...

Django框架-使用celery(一):django使用celery的通用配置,不受版本影响
目录 一、依赖包情况 二、项目目录结构 2.1、怎么将django的应用创建到apps包 三、celery的配置 2.1、celery_task/celery.py 2.2、celery_task/async_task.py 2.3、celery_task/scheduler_task.py 2.4、utils/check_task.py 四、apps/user中配置相关处理视图 4.1、基本…...
nvue语法与vue的部分区别
文章目录 1、仅支持flex布局2、字体样式3、高度问题 1、仅支持flex布局 仅支持flex布局。而且默认的是 flex-direction: column; 2、字体样式 字体的样式,必须要写在 text 标签内,才能生效 错误示例: <!-- 错误示例 --> <div cl…...
Java 开发工具 IntelliJ IDEA
1. IntelliJ IDEA 简介 IntelliJ IDEA 是一款出色的 Java 集成开发环境(IDE),提供了丰富的功能和工具,支持多种语言和框架的开发,如 Java、Kotlin、Scala、 Android、Spring、Hibernate 等。IntelliJ IDEA 专注于提高…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...