欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 网页版五子棋项目的问题处理

网页版五子棋项目的问题处理

2025/4/2 5:09:34 来源:https://blog.csdn.net/2301_80381519/article/details/146765339  浏览:    关键词:网页版五子棋项目的问题处理

文章目录

  • config.WebSocketConfig
  • 将键值对加⼊OnlineUserManager中
  • 线程安全、锁
  • ObjectMapper来处理json
  • 针对多开情况的判定
  • 处理连接关闭、异常(玩家中途退出)后的不合理操作
  • 游戏大厅数据更新

config.WebSocketConfig

把MatchAPI注册进去

• 在addHandler 之后,再加上⼀个.addInterceptors(newHttpSessionHandshakeInterceptor()) 代码,这样可以把之前登录过程中往HttpSession中存放的数据(主要是User对象),到WebSocket的session中.⽅便后⾯的代码中获取到当前用户信息

// 通过 .addInterceptors(new HttpSessionHandshakeInterceptor() 这个操作来把 HttpSession ⾥的属性放到 WebSocket 的 session 中 // 参考: https://docs.spring.io/springframework/docs/5.0.7.RELEASE/spring-framework-reference/web.html#websocketserver-handshake// 然后就可以在 WebSocket 代码中 WebSocketSession ⾥拿到 HttpSession 中的 attribute.registry.addHandler(matchAPI, "/findMatch").addInterceptors(new HttpSessionHandshakeInterceptor());}

将键值对加⼊OnlineUserManager中

• 当玩家断开websocket连接,则将键值对从OnlineUserManager中删除
• 在玩家连接好的过程中,随时可以通过userId来查询到对应的会话,以便向客户端返回数据
由于存在两个⻚⾯,游戏⼤厅和游戏房间,使⽤两个哈希表来分别存储两部分的会话
在这里插入图片描述

线程安全、锁

由于handlerMatch 在单独的线程中调⽤.因此要考虑到访问队列的线程安全问题.需要加上锁
• 每个队列分别使⽤队列对象本⾝作为锁即可.
• 在⼊⼝处使⽤wait来等待,直到队列中达到2个元素及其以上,才唤醒线程消费队列

private void handlerMatch(Queue<User> matchQueue) {synchronized (matchQueue){try {// 很可能队列初始情况为0,用while循环检查,不能用if(匹配成功需要有两个玩家)while (matchQueue.size() < 2){matchQueue.wait();return;}//从队列中取出两个玩家User player1 = matchQueue.poll();User player2 = matchQueue.poll();System.out.println("匹配出了两个玩家:"+player1.getUsername()+" , "+player2.getUsername());//获取玩家的websocket的会话,告诉玩家 排到了WebSocketSession session1 = onlineUserManager.getFromGameHall(player1.getUserId());WebSocketSession session2 = onlineUserManager.getFromGameHall(player2.getUserId());//理论上来说,匹配队列中的玩家一定是在线状态(前面已经处理过,断开连接的玩家会被移除匹配队列//为了谨慎,再进行一次判断if (session1 == null){//玩家1不在线就把玩家2放回到匹配队列中matchQueue.offer(player2);return;}if (session2 == null){//玩家2不在线就把玩家1放回到匹配队列中matchQueue.offer(player1);return;}//TODO 把这两个玩家放到一个游戏房间中Room room = new Room();roomManager.add(room,player1.getUserId(),player2.getUserId());//给玩家反馈信息 匹配到了MatchResponse response1 = new MatchResponse();response1.setOk(true);response1.setMessage("matchSuccess");session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response1)));MatchResponse response2 = new MatchResponse();response2.setOk(true);response2.setMessage("matchSuccess");session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response2)));}catch (IOException | InterruptedException e){e.printStackTrace();}
public void add(User user){if (user.getScore() < 2000){synchronized (normalQueue){normalQueue.offer(user);normalQueue.notify();}System.out.println("把玩家"+user.getUsername()+"加入到了 normalQueue 中!");} else if (user.getScore() >= 2000 && user.getScore() < 3000) {synchronized (highQueue){highQueue.offer(user);highQueue.notify();}System.out.println("把玩家"+user.getUsername()+"加入到了 highQueue 中!");}else {synchronized (veryHighQueue){veryHighQueue.offer(user);veryHighQueue.notify();}System.out.println("把玩家"+user.getUsername()+"加入到了 veryHighQueue 中!");}}
public void remove(User user){if (user.getScore() < 2000){synchronized (normalQueue){normalQueue.remove(user);}System.out.println("把玩家"+user.getUsername()+"移除normalQueue队列");} else if (user.getScore() >= 2000 && user.getScore() < 3000) {synchronized (highQueue){highQueue.remove(user);}System.out.println("把玩家"+user.getUsername()+"移除highQueue队列");}else {synchronized (veryHighQueue){veryHighQueue.remove(user);}System.out.println("把玩家"+user.getUsername()+"移除veryHighQueue队列");}}

ObjectMapper来处理json

MatchResponse response = new MatchResponse();response.setOk(false);response.setReason("您尚未登录! 不能进行匹配!");session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));//TextMessage--一个文本格式的websocket数据 通过ObjectMapper把对象转成JSON字符串!

针对多开情况的判定

//  获取玩家身份信息(哪个玩家在游戏大厅中 建立了连接)//   (注意!!!可能出现玩家身份信息为空的现象----玩家直接通过 /game_hall.html 进入游戏大厅try {User user = (User) session.getAttributes().get("user");//判断当前用户是否已经登录,禁止多开WebSocketSession webSocketSession = onlineUserManager.getFromGameHall(user.getUserId());if( webSocketSession != null || onlineUserManager.getFromGameRoom(user.getUserId()) != null){MatchResponse response = new MatchResponse();response.setOk(true);response.setReason("此用户已登录! 禁止重复登录!");response.setMessage("repeatConnection");session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));//session.close();//连接断开return;}
//判断用户有没有多开if (onlineUserManager.getFromGameHall(user.getUserId()) != null|| onlineUserManager.getFromGameRoom(user.getUserId()) !=null){response.setOk(false);response.setReason("禁止多开游戏");session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));return;}
success: function(data) { // bodyconsole.log(JSON.stringify(data));if (data && data.userId > 0) {// 登录成功, 跳转到游戏⼤厅alert("登录成功!")location.assign('/game_hall.html');} else {alert("登录失败! 用户名密码错误! 或者 该账号正在游戏中!");}}

下线的时候注意针对多开情况的判定,避免错误删除玩家

try {//玩家下线,移除User user = (User) session.getAttributes().get("user");//  把该玩家设置为下线状态// 避免移除多开情况时,错误删除WebSocketSession webSocketSession = onlineUserManager.getFromGameHall(user.getUserId());if (webSocketSession == session){onlineUserManager.exitGameHall(user.getUserId());}matcher.remove(user);//玩家正在匹配中,连接断开,移除玩家}

处理连接关闭、异常(玩家中途退出)后的不合理操作

此时连接已经关闭,不应该再发送信息给客户端

catch (NullPointerException e){e.printStackTrace();//连接已经关闭,不应该再发送信息给客户端
//            //把 当前用户未登录 这个信息返回回去
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录! 不能进行匹配!");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
//            //TextMessage--一个文本格式的websocket数据 通过ObjectMapper把对象转成JSON字符串!}

用户操作不可控,谨慎处理可能发生的情况

WebSocketSession existSession = onlineUserManager.getFromGameRoom(user.getUserId());if (existSession != session){System.out.println("当前的会话不是玩家游戏中的会话, 不做处理!");return;}

游戏大厅数据更新

对局结束后,分数、对局数会发生改变,因此游戏大厅中的数据需要从数据库中获取

public Object getUserInfo(HttpServletRequest req){try {HttpSession httpSession = req.getSession(false);User user = (User) httpSession.getAttribute("user");//去数据库中找最新的数据(一轮比赛后数据会有变化User newUser = userMapper.selectByName(user.getUsername());return newUser;}catch (NullPointerException e){return new User();}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词