[网页五子棋][对战模块]处理连接成功,通知玩家就绪,逻辑问题(线程安全,先手判定错误)

article/2025/8/12 22:30:46

文章目录

  • 处理连接成功
  • 通知玩家就绪
  • 逻辑图
  • 问题 1:线程安全
  • 问题 2:先手判定错误
    • 两边都是提示:轮到对方落子![image.png](https://i-blog.csdnimg.cn/img_convert/c570cd26eadbe87ed467bc4edaa7945e.png)

处理连接成功

实现 GameAPIafterConnectionEstablished 方法

  • 首先需要检测用户的登录状态(从 session 中拿到当前用户信息)
  • 然后要判定当前玩家是否是在房间中
  • 接下来进行多开判定,如果玩家已经在游戏中,则不能再次连接
  • 把两个玩家放到对应的房间对象中,当两个玩家都建立了连接,房间就放满了,这个时候通知双方都准备就绪
  • 如果有第三个玩家尝试也想加入房间,则给出一个提示,房间已经满了
@Override  
public void afterConnectionEstablished(WebSocketSession session) throws Exception {  GameReadyResponse resp = new GameReadyResponse();  // 1. 先获取到用户的身份信息(从 HttpSession 里面拿到当前用户的对象)  User user = (User) session.getAttributes().get("user");  if(user == null) {  resp.setOk(false);  resp.setReason("用户尚未登录!");  session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));  return;  }  // 2. 判定当前用户是否已经在房间里(拿房间管理器 RoomManager 进行查询)  Room room = roomManager.getRoomByUserId(user.getUserId());  if (room == null) {  // 如果为 null,当前没有找到对应的房间,就是该玩家还没有匹配到  resp.setOk(false);  resp.setReason("用户尚未匹配到!");  session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));  return;  }  // 3. 判定当前是不是多开(该用户是不是已经在其他地方进入游戏了)  //    前面准备了一个 OnlineUserManager    if (onlineUserManager.getFromGameRoom(user.getUserId()) != null  || onlineUserManager.getFromGameHall(user.getUserId()) != null) {  // 如果一个账号,一边是在游戏大厅,一边是在游戏房间,也视为多开  resp.setOk(false);  resp.setReason("禁止多开游戏页面!");  session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));  }  // 4. 设置当前玩家上线  onlineUserManager.enterGameHall(user.getUserId(), session);  // 5. 把两个玩家加入到游戏房间中  //    当前这个逻辑是在 game_room.html 页面加载的时候进行的,  //    前面的创建房间/匹配过程,是在 game_hall.html 页面中完成的  //    因此前面匹配到对手之后,需要经过页面跳转,来到 game_room.html 才算正式进入游戏房间(玩家准备就绪)  //    直行到当前逻辑,说明玩家已经页面跳转成功了  //    页面跳转是很有可能出现失败的情况的(成本高,风险大)  if (room.getUser1() == null) {  // 第一个玩家还未加入房间,就把当前连上 websocket 的玩家作为 user1 加入到房间中  room.setUser1(user);  // 把先连入房间的玩家作为先手  room.setWhiteUser(user.getUserId());  System.out.println("玩家 " + user.getUsername() + " 作为玩家1,已经准备就绪!");  return;}  if (room.getUser2() == null) {  // 如果进入这个逻辑,说明玩家1 已经加入房间,现在要给当前玩家作为玩家2  room.setUser2(user);  System.out.println("玩家 " + user.getUsername() + " 作为玩家2,已经准备就绪!");  // 当两个玩家都加入成功之后,就要让服务器,给这两个玩家都返回 websocket 的响应数据  // 通知这两个玩家:游戏双方都已经准备好了  // 通知玩家1  noticeGameReady(room, room.getUser1(), room.getUser2());  // 通知玩家2  noticeGameReady(room, room.getUser2(), room.getUser1());  return;  }  // 6. 此处又有玩家尝试连接同一个房间,就提示报错  //    这种情况理论上是不存在的,为了让程序更加的健壮,还是做一个判定和提示  resp.setOk(false);  resp.setReason("当前房间已满,你不能加入房间!");  session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
}  private void noticeGameReady(Room room, User thisUser, User thatUser) throws IOException {  GameReadyResponse resp = new GameReadyResponse();  resp.setMessage("gameReady");  resp.setOk(true);  resp.setReason("");  resp.setRoomId(room.getRoomId());  resp.setThisUserId(thisUser.getUserId());  resp.setThatUserId(thatUser.getUserId());  resp.setWhiteUser(room.getWhiteUser());  // 把当前的响应数据传回给玩家  WebSocketSession session = onlineUserManager.getFromGameRoom(thisUser.getUserId());  session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
}

image.png

  • 之前已经写了一个 OnlineUserManager 对象了,也确实能够管理一些用户的在线状态
  • 但是这个状态仅仅是局限在 game_hall 这个页面中
  • 现在我们已经是在 game_room 中了

image.png

  • 之前在退出 game_hall 页面的时候,就会断开 websocket 连接,也就会在服务器的 OnlineUserManager 中删掉对应的元素

因此玩家从游戏大厅离开之后,进入游戏房间页面的时候,就需要重新管理用户的在线状态了

通知玩家就绪

@Override  
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {  User user = (User) session.getAttributes().get("user");  if (user == null) {  // 此处我们简单处理,在断开连接的时候就不给客户端返回响应了  return;  }  WebSocketSession existSession = onlineUserManager.getFromGameRoom(user.getUserId());  if(session == existSession) {  // 加上这个判定,目的是为了避免在多开的情况下,第二个用户退出连接动作,导致第一个用户的会话被删除  onlineUserManager.exitGameRoom(user.getUserId());  }  System.out.println("当前用户 " + user.getUsername() + " 游戏房间连接异常!");  
}

逻辑图

对战模块-连接房间.png

问题 1:线程安全

在玩家 1 连入服务器和玩家 2 连入服务器这两个操作,就是并发的

  • 不能保证是上面逻辑图中 1 先建立,2 后建立的顺序
  • 这就意味着代码中的这段逻辑是存在多线程环境下调用的,可能会出现线程安全问题 image.png
  • 我们就要把这里的逻辑判定,使用锁保护起来,避免多个客户端都认为自己是先手方

需要竞争的资源是什么,就对什么加锁

  • 对谁加锁,针对这个对象访问的时候才有互斥效果
  • 此时我们是多个线程在同时访问、修改同一个 room 对象
  • 所以我们需要针对 room 对象加锁

image.png|529

  • 要保证玩家 1 和 2 要互斥,玩家 3 和 4 要互斥,玩家 5 和 6 要互斥
  • 同个房间里的两个对象才会有竞争,非同房里面的玩家互不干扰image.png|471

问题 2:先手判定错误

两边都是提示:轮到对方落子image.png

image.png|366

  • 客户端代码中尝试获取响应中的 isWhite 字段
  • 但是实际响应的数据中,根本就灭有 isWhite 字段,有的是 whiteUser 字段image.png
  • 因此代码中进行取这个字段,就都取到了一个 undefined,这里的判断结果都为 false,所以在先手选择都是选择对方image.png

解决办法:image.png
image.png


http://www.hkcw.cn/article/PyJArnTTCI.shtml

相关文章

Python训练打卡Day39

图像数据与显存 知识点回顾 图像数据的格式:灰度和彩色数据模型的定义显存占用的4种地方 模型参数梯度参数优化器参数数据批量所占显存神经元输出中间状态 batchisize和训练的关系 一、图像数据的格式 1.1灰度图像 作为图像数据,相较于结构化数据&#x…

pycharm打印时不换行,方便对比观察

原来: 优化: import torch torch.set_printoptions(linewidth200) 优化结果:

Practice 2025.6.1—— 二叉树进阶面试题(2)

文章目录 二叉树进阶面试题(2)Leetcode_144 二叉树的前序遍历(使用非递归)Leetcode_94 二叉树的中序遍历(使用非递归)Leetcode_145 二叉树的后序遍历(使用非递归) 二叉树进阶面试题(2) 本篇文章将继续进行二叉树的进阶面试题的讲解,其中,本部分将重点针…

DOCKER使用记录

1、拉取镜像 直接使用docker pull <image>&#xff0c;大概率会出现下面的报错信息&#xff1a; (base) jetsonyahboom:~$ docker pull ubuntu:18.04 Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while …

Vert.x学习笔记-EventLoop与Context的关系

Vert.x学习笔记 1. EventLoop 的核心作用2. Context 的核心作用3. EventLoop 与 Context 的关系1. 事件循环&#xff08;EventLoop&#xff09;的核心职责2. 上下文&#xff08;Context&#xff09;的核心职责3. 事件循环与上下文的关系&#xff08;1&#xff09;一对一绑定&am…

LTSPICE仿真电路:(三十一)HOWLAND电流源

1.HOWLAND电流源 推导过程&#xff1a;这个运放是正负反馈都存在&#xff0c;但负反馈是大于正反馈的&#xff0c;因正反馈多出一个Rload&#xff0c;所以可以使用虚短续断&#xff0c;运放的U等于U-&#xff0c;负反馈处得出Uout与U-的关系&#xff0c;再利用正相端节点电流算…

LLaMA-Factory - 批量推理(inference)的脚本

scripts/vllm_infer.py 是 LLaMA-Factory 团队用于批量推理&#xff08;inference&#xff09;的脚本&#xff0c;基于 vLLM 引擎&#xff0c;支持高效的并行推理。它可以对一个数据集批量生成模型输出&#xff0c;并保存为 JSONL 文件&#xff0c;适合大规模评测和自动化测试。…

引擎下线缺陷检测系统ENAgent

引擎下线缺陷检测系统ENAgent采用信号处理技术以及人工智能技术对引擎生产线下线的各种引擎在生产线上进行缺陷实时检测&#xff0c;通过振动信号、声纹信号等信号融合集成&#xff0c;在线实时判断其是否存在缺陷以及进行故障诊断。ENAgent系统采用全Python语言&#xff0c;以…

【量化交易学习】布林线(BOLL)指标

目录 1. 布林线&#xff08;BOLL&#xff09;指标定义与构成1.1 定义1.2 布林线的构成 2. BOLL&#xff08;布林线&#xff09;的应用场景3. BOLL指标的研判标准3.1 BOLL指标中的上、中、下轨线的意义3.2 BOLL指标中的上、中、下轨线之间的关系3.3 K线和布林线上、中、下轨之间…

ArcGIS Pro 创建渔网格网过大,只有几个格网的解决方案

之前用ArcGIS Pro创建渔网的时候&#xff0c;发现创建出来格网过大&#xff0c;只有几个格网。 后来查阅资料&#xff0c;发现是坐标不对&#xff0c;导致设置格网大小时单位为度&#xff0c;而不是米&#xff0c;因此需要进行坐标系转换&#xff0c;网上有很多资料讲了ArcGIS …

java27

1.IO流 FileOutPutStream字节输出流基本用法&#xff1a; 一次性写入一个字符串的内容&#xff1a; 注意&#xff1a;\r或者\n表示把普通的r或者n的字符转义成回车的意思&#xff0c;所以不需要\\ FileInputStream字节输入流基本用法 -1在ASCII码里面对应的符号&#xff1a; 不…

Windows设置之RDP文件用户密码

1、远程桌面另存为rdp文件 2、编辑rdp文件&#xff0c;添加用户名密码信息 username:s:<用户名> password 51:b:<加密后的密码> 3、<加密后的密码>通过PowerShell命令或者 ("<密码>" | ConvertTo-SecureString -AsPlainText -Force) | Conve…

day025-网络基础-DNS与ARP协议

文章目录 1. DNS服务1.1 DNS解析流程1.2 查看本地DNS缓存&#xff08;Windows&#xff09;1.3 查看详细DNS解析流程1.4 排查DNS故障 2. 面试题&#xff1a;用户访问网站过程2.1 抓包 3. ARP协议3.1 命令查看3.2 抓包 4. ICMP协议4.1 禁用ping 5. 踩坑记录1. **为什么解析域名时…

SEO长尾关键词优化实战

内容概要 在长尾关键词优化实践中&#xff0c;系统化的策略设计与执行路径直接影响流量获取效率与转化质量。本文从行业竞争度评估切入&#xff0c;通过多维指标拆解目标关键词的流量价值与操作成本&#xff0c;帮助从业者建立科学的资源分配模型&#xff1b;同时聚焦用户搜索…

复杂业务场景下 JSON 规范设计:Map<String,Object>快速开发 与 ResponseEntity精细化控制HTTP 的本质区别与应用场景解析

Moudle 1 Json使用示例 在企业开发中&#xff0c;构造 JSON 格式数据的方式需兼顾 可读性、兼容性、安全性和开发效率&#xff0c;以下是几种常用方式及适用场景&#xff1a; 一、直接使用 Map / 对象转换&#xff08;简单场景&#xff09; 通过 键值对集合&#xff08;如 M…

Oracle正则表达式学习

目录 一、正则表达简介 二、REGEXP_LIKE(x,匹配项) 三、REGEXP_INSTR 四、REGEXP_SUBSTR 五、REGEXP_REPLACE 一、正则表达简介 相关网址&#xff1a; https://cloud.tencent.com/developer/article/1456428 https://www.cnblogs.com/lxl57610/p/8227599.html https://…

【HW系列】—溯源与定位—Windows入侵排查

文章目录 实在不会手动&#xff0c;打开一个杀毒软件&#xff0c;全盘扫描一、入侵排查思路与流程1. 常见应急响应事件分类2. 入侵排查流程图 二、Windows账户安全排查&#xff08;D盾&#xff0c;微步沙箱&#xff09;1. 正常账户 vs 黑客账户区别2. 自动账户排查3. 隐藏账户与…

【机器学习基础】机器学习入门核心:Jaccard相似度 (Jaccard Index) 和 Pearson相似度 (Pearson Correlation)

机器学习入门核心&#xff1a;Jaccard相似度 &#xff08;Jaccard Index&#xff09; 和 Pearson相似度 &#xff08;Pearson Correlation&#xff09; 一、算法逻辑Jaccard相似度 (Jaccard Index)**Pearson相似度 (Pearson Correlation)** 二、算法原理与数学推导1. Jaccard相…

CVE-2021-28164源码分析与漏洞复现

漏洞概述 漏洞名称&#xff1a;Jetty 路径解析逻辑漏洞导致 WEB-INF 敏感信息泄露 漏洞编号&#xff1a;CVE-2021-28164 CVSS 评分&#xff1a;7.5 影响版本&#xff1a;Jetty 9.4.37 - 9.4.38 修复版本&#xff1a;Jetty ≥ 9.4.39 漏洞类型&#xff1a;路径遍历/信息泄露 C…

微软常用运行库合集(VisualC++)2025.04.22

软件下载 【名称】&#xff1a;微软常用运行库合集(Visual C)2024.11.07 【大小】&#xff1a;76 .7MB 【语言】&#xff1a;简体中文 【安装环境】&#xff1a;Win7/Win8/Win10/Win11 【迅雷网盘下载】&#xff1a; 链接&#xff1a;https://pan.xunlei.com/s/VOCJ3CDOT6HEhQN…