首页 > 其他分享 >websocket使用

websocket使用

时间:2023-12-13 17:22:32浏览次数:23  
标签:webSocketMap websocket String conferenceId 使用 userToken logger message

WEBSocket(客户端和服务器能够双向同时传输数据): 应用层协议,客户端和服务器建立连接时采用http握手方式,建立连接后利用http协议的Upgrade属性将协议变更为WebSocket协议(通过TCP协议来传输数据)

http和websocket
相同点:1 都是建立在TCP之上,通过TCP协议来传输数据; 2 都是可靠性传输协议; 3 都是应用层协议
不同点:1 WebSocket支持持久连接,HTTP不支持持久连接 2 WebSocket是双向通信协议,HTTP是单向协议,只能由客户端发起,做不到服务器主动向客户端推送信息。

后端java使用websocket:

依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

 创建WebSocket服务端点

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/imserver/{conferenceId}/{userToken}", configurator = WebSocketConfigurator.class) @Component public class WebSocketServer {
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static final ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>(); /**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session; /**
* 接收 userToken
*/
private String userToken = ""; //可用@Autowired正常注入 @OnOpen
public void onOpen(Session session, @PathParam("userToken") String userToken, @PathParam("conferenceId") String conferenceId) throws IOException { final Map<String, Object> properties = session.getUserProperties();
logger.info("open输出当前对象: " + this);
this.session = session;
this.userToken = userToken; //根据userToken判断webSocketMap中是否已经有相同的key,如果有,先把旧的连接断开再加入新连接 for (Map.Entry<String, WebSocketServer> entry : webSocketMap.entrySet()) {
String preUserToken = entry.getKey();//先登陆的 if (userToken.equals(preUserToken)) {
WebSocketServer webSocket = entry.getValue(); webSocketMap.get(preUserToken).onClose(); } } webSocketMap.put(userToken, this); } @OnClose
public void onClose() {
if (webSocketMap.containsKey(userToken) && webSocketMap.get(userToken) == this) {
logger.info("删除时 webSocketMap 成员数量为 {}, token 为 {} ,onClose 要删的对象是 {}", webSocketMap.size(), userToken, webSocketMap.get(userToken));
webSocketMap.remove(userToken);
}
logger.info("用户 memberId = {}, name = {}, token = {} 退出,当前在线人数为 {}", memberId, name, userToken, getOnlineCount());
}   /**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/ @OnMessage
public void onMessage(String message, Session session) throws IOException {
logger.debug("接收到用户 {} 消息,报文: {}", userToken, message);
JSONObject jsonMsg;
try {
jsonMsg = JSONObject.parseObject(message);
} catch (com.alibaba.fastjson.JSONException e) {
logger.warn("WebSocket服务收到了非 JSON 消息,报文:{}", message);
return;
}
if (jsonMsg != null) { //业务逻辑
String type = jsonMsg.getString("type");
String uuid = jsonMsg.getString("uuid");
WebSocketEnum anEnum = WebSocketEnum.getEnum(type); //前端根据用户操作,给后端发送不同类型的消息,后端根据消息类型分别处理 switch (anEnum) { // 心跳 case heartbeat:
// 进行心跳包反馈
sendInfo(jsonMsguserToken);
break;
//倒计时的开启、关闭
case countPlayStop:
sendCountdownInfoForAll(jsonMsg);
break; //切换议题
case conferenceIssue: //修改会议状态
case conferenceStatus: //开启、关闭同屏
case sameScreenStatus: //切换资料
case conferenceAttachment:
//如果是接口调用去查当前用户
Member userInfo = getUserinfo.getUserInfo(this.userToken);
speakerId = userInfo.getId();
case conferenceSync:
if (anEnum == conferenceSync) {
Conference conference = conferenceService.getConferenceByAttachmentId(attachmentId);
if (conference == null) {
// attachmentId已被删除
JSONObject obj = new JSONObject();
obj.put("type", "deletedType");
obj.put("conferenceId", conferenceId);
obj.put("attachmentId", attachmentId);
obj.put("message", "当前会议资料已删除,请点击确认按钮更新会议资料");
try {
sendInfo(obj.toJSONString(), userToken);
} catch (IOException e) {
throw new RuntimeException(e);
}
return;
}
}
// 主控轮询修改版本号
ConferenceStatusDTO conferenceStatus = conferenceStatusComponent.getConferenceStatusById(conferenceId);

if (conferenceStatus != null) {
logger.debug("主控轮询 conferenceSync 操作,用户 {}, 当前会议状态信息:{},token 为 {},", memberId, JacksonHelper.toJsonString(conferenceStatus), userToken);
// 切换议题,主讲轮询的数据是切换议题前的数据,不修改
// 切换议题会有 >= 俩个值不同
// 议题是否匹配
boolean notMatchIssue = issueId.longValue() != conferenceStatus.getIssueId();
// 主讲人是否匹配
boolean notMatchSpeaker = speakerId.longValue() != conferenceStatus.getSpeakerId();
// 附件是否匹配
boolean notMatchAttachment = attachmentId.longValue() != conferenceStatus.getAttachmentId();
if (notMatchIssue && (notMatchSpeaker || notMatchAttachment)) {
logger.warn("主控轮询上报信息不匹配,议题是否匹配:{},上报主讲人是否匹配:{},附件是否匹配:{}", false, !notMatchSpeaker, !notMatchAttachment);
return;
}
// 其他情况每次只有一个不相同
if (notMatchSpeaker || notMatchIssue || notMatchAttachment) {
logger.warn("主控轮询上报信息不匹配,当前用户为 {},token 为 {},议题是否匹配:{},主讲人是否匹配:{},附件是否匹配:{}", memberId, userToken, !notMatchIssue, !notMatchSpeaker, !notMatchAttachment);
boolean success = conferenceStatusComponent.changeVersion(conferenceId, issueId, attachmentId, speakerId, type, false);
if (success) {
// 同步主控端消息推送
this.masterSyncSend(jsonMsg);
}
}
}
default:
if (StringUtils.isNotBlank(uuid)) {
//messageMap.remove(uuid);
Iterator<Map<String, String>> iterator = messageVector.iterator();
while (iterator.hasNext()) {
Map<String, String> next = iterator.next();
if (uuid.equals(next.get("uuid"))) {
iterator.remove();
}
}
logger.info("收到客户端消息用户:" + userToken + ",已清除消息:" + uuid);
//logger.warn("用户:" + userId + ",已清除消息:" + uuid);
}
break;
}
}
} public static void sendInfo(String message, @PathParam("userToken") String userToken) throws IOException {
//log.info("发送消息到:"+userId+",报文:"+message);
if (StringUtils.isNotBlank(userToken) && webSocketMap.containsKey(userToken)) {
webSocketMap.get(userToken).sendMessage(message);
} else {
logger.warn("用户【{}】不在线,发送消息失败,消息内容为 {} ", userToken, message);
}
} public static void sendCountdownInfoForAll(Map<String, Object> map) throws IOException {
//优先清理垃圾连接
cleanGcConnect();
for (Map.Entry<String, WebSocketServer> entry : webSocketMap.entrySet()) {
//只给同一会议中的人发
String conferenceId = map.get("conferenceId").toString();
if (StringUtils.equals(entry.getValue().conferenceId, conferenceId)) {
String userToken = entry.getKey();
sendInfo(JSON.toJSONString(map), userToken);
}
}
}
}

  

标签:webSocketMap,websocket,String,conferenceId,使用,userToken,logger,message
From: https://www.cnblogs.com/1--2/p/17899055.html

相关文章

  • Asp.net core Net6.0 Webapi 项目如何优雅地使用内存缓存
    前言缓存是提升程序性能必不可少的方法,Asp.netcore支持多级缓存配置,主要有客户端缓存、服务器端缓存,内存缓存和分布式缓存等。其中客户端缓和服务器端缓存在使用上都有比较大的限制,而内存缓和分布式缓存则比较灵活。内存缓存就是一种把缓存数据放到应用程序内存中的机制。本......
  • 使用element 2.14 实现表格虚拟滚动组件
    下述代码为组件实现代码复制即可食用,默认只展示一屏数据加两条全选存在些许问题,使用row-key时,如果行过多滚动时会不会很流畅特别需要注意的是行高必须要保持一致<template><divclass="t-table":id="TTableId"><el-tableref="el-table":tooltip-......
  • 大数据企业怎样使用IP代理进行数据抓取
    前言大数据企业通常需要从各种网站和在线平台上进行数据抓取和数据挖掘。然而,许多网站限制了对其内容的访问,使用IP代理是一种常见的解决方案。在本文中,我将介绍大数据企业如何使用IP代理进行数据抓取,并提供相应的代码示例。一、什么是IP代理IP代理是一种允许用户通过第三方服务器......
  • SQLite的下载和配置使用
    特性SQLite的设计目的是嵌入式SQL数据库引擎,它基于纯C语言代码,已经应用于非常广泛的领域内。SQLite在需要长时间存储时可以直接读取硬盘上的数据文件(.db),在无须长时间存储时也可以将整个数据库置于内存中,两者均不需要额外的服务器端进程,即SQLite是无须独立运行的数据库引......
  • Linux系统中curl命令使用笔记
    在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,用来请求Web服务器,它的名字就是客户端(client)的URL工具的意思,可以说是一款很强大的http命令行工具,它支持文件的上传和下载,是综合传输工具。可以看出它的参数非常多,a-z的字母,几乎都用到了,参数这么说,功能肯定很强大......
  • 项目使用第三方jar包SDK
    方式一、使用IDEA程序引入jar包1、首先,点他! 2、然后,点他! 3、再然后,点他! 4、最后,在这里选择自己需要上传的Jar包,收工结束!方式二、通过Maven添加到本地仓库,然后在运用依赖导入项1、首先,找到自己所在jar包的目录并输入cmd唤出控制台  2、然后,根据实际情况在控制台......
  • 【转载】SpringBoot2.x使用Assert校验(非单元测试)
    参考https://blog.csdn.net/yangshangwei/article/details/123105926环境环境版本操作windows10JDK11Springboot2.3.12.RELEASE注意引入的包为importorg.springframework.util.Assert;介绍对象和类型断言函数说明notNull()假设对......
  • Highcharts 使用SVGRenderer方法绘制极地图​
    需求展示如何创建一个极地图、设置样式,并使用SVGRenderer方法绘制解释说明的路径和文本。分析要使用Highcharts的SVGRenderer方法绘制极地图,可以按照以下步骤操作:首先,创建一个极地图实例,并设置所需的配置项;创建一个SVGRenderer实例,使用SVGRenderer的path方法绘制路径;可以......
  • 使用 npm-check-updates 检查项目的 npm 依赖项是否有更新
    一、安装npm-check-updates:npminstall-gnpm-check-updates二、使用:在项目根目录运行以下命令,检查所有项目依赖项的最新版本:ncu执行结果如下:红色=主要升级青色=小幅升级绿色=补丁升级更新版本:ncu-u注意备份或者提交代码,确保包文件处于版本控制......
  • 【JAVA】使用intellij IDEA将项目打包为jar包
    当你有一个能正常编译的项目,以springboot为例,有两步步骤打包配置打包一、打包配置1.点击右上角快捷按钮/文件-->项目结构,打开项目结构设置  2.项目结构-->Artifacts,如图所示选择 3.在CreateJARfromModules配置, 4.配置jar输出相关设置 二、打包1.构建......