使用java完成WebSocket自动主动断开连接功能

这篇具有很好参考价值的文章主要介绍了使用java完成WebSocket自动主动断开连接功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

项目中的需求是这样的:

一个页面实时刷新的功能,页面上的数据状态可能会随着操作实时改变,所以每个用户在使用的时候都希望能看到数据的最新状态。

我想到了两种解决方法:1.轮循,2.WebSocket

我们这里采用的是WebSocket来解决问题

然而在解决的过程中又发现了其他的问题

WebSocket在建立连接后,如果不是人为操作的话,他不会主动地进行断开,这样会导致数据安全问题。

下面是我解决问题的代码:

import javax.websocket.Session;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class WebSocketTokenExpirationCheckTask {

    // 保存session和过期时间的Map
    private static final Map<Session, Long> tokenExpirationMap = new ConcurrentHashMap<>();

    /**
     * 添加token和过期时间(也可以将token代替session作为参数,验证token有效性,来判断是否过期)
     */
    public static void addSessionExpiration(Session session, Long expirationTime) {
        tokenExpirationMap.put(session, expirationTime);
    }

    public static void removeSessionExpiration(Session session) {
        tokenExpirationMap.remove(session);
    }

    /**
     * 检查token是否过期
     */
    @Scheduled(fixedDelay = 60000) // 每60秒执行一次
    public void checkTokenExpiration() {
        long currentTimeMillis = System.currentTimeMillis();
        for (Session session : tokenExpirationMap.keySet()) {
            Long expirationTime = tokenExpirationMap.get(session);
            if (expirationTime != null && currentTimeMillis > expirationTime) {
                WebSocketServerPool.removeBySession(session); // 移除对应的连接(也可以将token作为参数,验证token有效性,来判断是否过期)
            }
        }
    }
}

这部分是提供了一个定时任务,每60秒去看一下,我们的连接是否过期了。

public class WebSocketServerPool {

    /**
     * WebSocket连接池
     */
    private static ConcurrentMap<Session, String> dataConnect = new ConcurrentHashMap<>();

    private static ConcurrentMap<Session, String> dataMessage = new ConcurrentHashMap<>();

    private static ConcurrentMap<Session, String> dataScene = new ConcurrentHashMap<>();

    /**
     * 将websocket连接,放入连接池
     *
     * @param session websocket连接
     */
    public static void addDataConnect(Session session, String screen) {
        dataConnect.put(session, screen);
        Iterator<Map.Entry<Session, String>> iterator = dataConnect.entrySet().iterator();
        synchronized (iterator) {
            //移除失效连接
            while (iterator.hasNext()) {
                Map.Entry<Session, String> entry = iterator.next();
                Session sessionNew = entry.getKey();
                Map<String, Object> userProperties = sessionNew.getUserProperties();
                if (null != userProperties && null != userProperties.get("ReadyState") && "0" != String.valueOf(userProperties.get("ReadyState"))) {
                    iterator.remove();
                }
            }
        }
    }

    public static void setDataMessage(Session session, String message) {
        dataMessage.put(session, message);
    }

    public static void setDataScene(Session session, String scene) {
        dataScene.put(session, scene);
    }

    /**
     * 将websocket连接从连接池中移除
     *
     * @param session websocket连接
     */
    public static void removeConnect(Session session) {
        Iterator<Map.Entry<Session, String>> iterator = dataConnect.entrySet().iterator();
        synchronized (iterator) {
            //主动移除连接
            while (iterator.hasNext()) {
                if (session.equals(iterator.next().getKey())) {
                    iterator.remove();
                }
            }
        }
    }

    /**
     * 获取连接池中所有连接
     *
     * @return 连接池所有数据
     */
    public static ConcurrentMap<Session, String> getDataConnect() {
        return dataConnect;
    }

    /**
     * 获取消息信息
     *
     * @return
     */
    public static ConcurrentMap<Session, String> getDataMessage() {
        return dataMessage;
    }

    /**
     * 获取数据场景
     *
     * @return
     */
    public static ConcurrentMap<Session, String> getDataScene() {
        return dataScene;
    }

    /**
     * Websocket消息推送
     *
     * @param session 连接
     * @param message 消息主体
     * @throws IOException I/O异常
     */
    public static void sendMessage(Session session, String message) throws IOException {
        session.getBasicRemote().sendText(message);
    }

    public static void removeBySession(Session session) {
//        for (Session session : dataConnect.keySet()) {
//            String sessionToken = dataConnect.get(token);
//            if (sessionToken != null && sessionToken.equals(token)) {
//                try {
//                    session.close(); // 主动关闭websocket连接
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//                removeConnect(session);
//                break;
//            }
//        }

        try {
            session.close(); // 主动关闭websocket连接
        } catch (IOException e) {
            e.printStackTrace();
        }
        removeConnect(session);
        WebSocketTokenExpirationCheckTask.removeSessionExpiration(session); // 从检查任务中移除该session(token)
    }
}

最后就是WebSocket服务代码了,这部分代码网上很多,核心就是在连接时(onOpen)将session和过期时间存入Map集合中,你也可以将token作为参数传递进来。文章来源地址https://www.toymoban.com/news/detail-469950.html

import com.zzyc.web.config.WebSocketServerPool;
import com.zzyc.web.service.IOrbitsService;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Component;


@ServerEndpoint("/webSocket/{userId}")
@Component
@Slf4j
public class WebSocketServer {

    /**
     * 建立连接成功调用 (Session + 场景ID)
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("userId") String screen) throws IOException {
        log.info("[onOpen][session({}) 接入, [screen: {}]", session, screen);
        WebSocketTokenExpirationCheckTask.addSessionExpiration(session, System.currentTimeMillis() + 30 * 60 * 1000); // 过期时间为30分钟
        WebSocketServerPool.setDataScene(session,"1");
        WebSocketServerPool.addDataConnect(session,screen);
    }


    /**
     * 关闭连接时调用
     * @param session 连接
     */
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        log.info("[onClose][session({}) 连接关闭。关闭原因是({})}]", session, closeReason);
        WebSocketServerPool.removeConnect(session);
    }

    /**
     * 错误时调用
     * @param session 连接
     * @param throwable 异常
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.info("[onClose][session({}) 发生异常]", session, throwable);
        WebSocketServerPool.removeConnect(session);
    }

    /**
     * 收到客户端信息后,根据接收到的信息进行处理
     * @param session 连接
     * @param message 数据消息
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        WebSocketServerPool.setDataMessage(session, message);
        log.info("[onOpen][session({}) 接收到一条消息({})]", session, message);
        // TODO: 2023/04/11 对于客户端发送的指令信息,解析后进行对应的逻辑处理
    }

    private void sendMessage(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            System.out.println("Error sending message to session " + session.getId() + ": " + e.getMessage());
        }
    }

}

这样就可以将WebSocket连接进行关闭了

到了这里,关于使用java完成WebSocket自动主动断开连接功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 保持websocket长时间连接永不断开

    1、定期发送心跳包(ping/pong) 客户端和服务器端都需要定期发送ping消息,并相应得到pong消息,以确保连接仍然正常。如果超过一定时间没收到pong,需要主动关闭连接。 JS客户端代码: Python客户端代码: java服务器端代码 2、捕获关闭连接事件并重连websocket JS客户端代码: Pyth

    2024年02月16日
    浏览(53)
  • mac使用VsCode远程连接服务器总是自动断开并要求输入密码的解决办法

    在mac中使用vscode远程连接服务器,时常会出现自动断开并要求重新输入服务器密码的问题,接下来让我们来解决它: 1、首先,在本地创建公钥: 这条命令执行之后,出现提示直接回车即可;直到遇到Overwrite (y/n)?  输入y,之后继续回车,如下图:  2、将本地mac密匙的 id_rs

    2024年02月10日
    浏览(60)
  • 【go】gorilla/websocket如何判断客户端强制断开连接

    当客户端因为某些问题异常关闭连接时,可以判断关闭连接的异常类型 通过调用websocket.IsCloseError或websocket.IsUnexpectedCloseError即可 其中github源码如下 异常类型如下

    2024年02月16日
    浏览(60)
  • Vue中WebSocket链接中断、心跳机制防止自动断开

    1、WebSocket链接中断原因 WebSocket断开的原因有很多,最好在WebSocket断开时,将错误打印出来。 二、心跳机制防止自动断开 WebSocket在一段时间内没有进行通讯便会自读断开链接,可以每隔30秒或一分钟向服务器发送一次通讯防止链接终端

    2024年02月16日
    浏览(45)
  • SpringCloudAlibaba 应用webSocket,解决连接成功后会立刻断开等问题

    最近公司有个大屏,需要做一个实时报警的功能,这就用到了webSocket技术,这个帖子就用来记录学习过程中的遇到的问题,如下是想要达到的效果图  1.第一步肯定是先导入依赖 这里记录第一个坑点,就是可能有的小伙伴会在启动的时候报错,这个是因为websocket和tomcat有冲突

    2024年02月11日
    浏览(57)
  • Java连接websocket优雅断线、重连功能

          为了实现优雅重连和重试,您需要在代码中添加一些逻辑来处理连接失败或断开连接的情况。 实现代码如下:

    2024年02月10日
    浏览(37)
  • 【好书精读】网络是怎样连接的 之 数据收发完成之后 从服务器断开并删除套接字

     ( 该图由AI制作 ) 目录 数据收发完成后协议栈要执行的操作 数据发送完毕后断开连接 删除套接字 数据收发操作小结 第一步是创建套接字 然后 客户端会向服务器发起连接操作 数据收发阶段 执行断开操作 前面讲了: 创建套接字到连接 、 收发数据 、 断开连接 、 今天讲

    2024年02月10日
    浏览(55)
  • java中使用sockjs、stomp完成websocket通信

    主要配置 握手拦截(这套方案好像前端无法补充Header,就不在这里做权限校验)这里采用的方法是直接问号拼接token,前端 new SockJS(这里带问号),sockjs使用的是http所以没毛病,本文使用的是OAuth2权限校验 之后可以设置握手之后的身份注入(配置了这个可以在单对单订阅时直接使用) 储

    2024年02月10日
    浏览(36)
  • 启动Docker后ssh连接自动断开且无法连接

    CentOS7.9在启动Docker之后现卡死,ssh远程连接(XShell)自动断开且无法再次连接,仅重启后方能连接,但启动Docker之后依旧出现前面的相同情况的问题解决方案 1、问题描述 CentOS环境启动Docker后卡住,此后会发现ssh远程连接被断开,且此后无法连接服务器。 具体情况如下图:

    2024年02月05日
    浏览(41)
  • selenium自动化DevTools连接断开问题

    使用Selenium的无头模式下,出现了DevTools连接断开的问题: 报错如下所示: 以上问题属于DevTools连接超时自动中断了,可能出现的问题: 1. 版本不匹配:Selenium与浏览器或驱动程序的版本可能不兼容。请确保使用的Selenium版本与浏览器和驱动程序的版本相匹配。 2. 驱动程序问

    2024年02月16日
    浏览(101)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包