有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如何在JavaSpringTomcat中快速关闭无响应websocket?

我有一个实时应用程序,客户端使用WebSocket连接SpringFramework服务器,该服务器运行SpringBootTomcat。我希望服务器能够快速(在5秒内)检测到客户端何时因网络断开连接或其他问题而停止响应,并关闭websocket

我试过了

  1. 将文档中描述的最大会话空闲超时设置为“配置WebSocket引擎” http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html

    @Bean
    public WebSocketHandler clientHandler() {
        return new PerConnectionWebSocketHandler(ClientHandler.class);
    }
    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = 
            new ServletServerContainerFactoryBean();
        container.setMaxSessionIdleTimeout(5000);
        container.setAsyncSendTimeout(5000);
        return container;
    }
    

我不确定这是否正确实现,因为我看不到ServletServerContainerFactoryBean和我这一代ClientHandler之间的链接

  1. 每2.5秒从服务器发送ping消息。在我通过断开网络连接手动断开客户端连接后,服务器会愉快地再发送ping 30多秒,直到出现传输错误

  2. 1和2同时进行

  3. 1和2,并在应用程序中设置server.session-timeout = 5。属性

我的测试方法是:

  1. 将websocket从笔记本电脑客户端连接到Tomcat服务器
  2. 使用物理交换机关闭笔记本电脑上的网络连接
  3. 等待Tomcat服务器事件

Spring FrameworkTomcat服务器如何快速检测到客户端已断开连接或没有响应关闭websocket


共 (4) 个答案

  1. # 1 楼答案

    我最终采用的方法是实现一个应用层乒乓协议

    • 服务器向客户端发送周期为p的ping消息
    • 客户端用pong消息响应每个ping消息
    • 如果服务器发送超过n条ping消息而未收到pong响应,则会生成超时事件
    • 如果客户端在n*p时间内没有收到ping消息,它还可以生成超时事件

    应该有一种更简单的方法在底层TCP连接中使用超时来实现这一点

  2. # 2 楼答案

    由于这个问题和最受欢迎的答案都很老了,我们想添加一种最简单的方法来实现spring-websocket实现

    参见第4.4.8. Simple Broker

    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    
        private TaskScheduler messageBrokerTaskScheduler;
    
        @Autowired
        public void setMessageBrokerTaskScheduler(TaskScheduler taskScheduler) {
            this.messageBrokerTaskScheduler = taskScheduler;
        }
    
        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
    
            registry.enableSimpleBroker("/queue/", "/topic/")
                    .setHeartbeatValue(new long[] {10000, 20000})
                    .setTaskScheduler(this.messageBrokerTaskScheduler);
    
            // ...
        }
    }
    

    返回connect响应帧时,websocket服务器需要发送hearbeat参数以启用客户端的ping

    如果您在客户端使用SOCKJS实现,那么不需要额外的代码将align添加到PING/PONG实现中

  3. # 3 楼答案

    ServletServerContainerFactoryBean只是在启动时通过Spring配置配置底层JSR-356WebSocketContainer。如果你往里面看,你会发现这是微不足道的

    从我在Tomcat代码中看到的有关maxSessionIdleTimeout处理的内容来看,WsWebSocketContainer#backgroundProcess()方法默认每10秒运行一次,以查看是否存在过期会话

    我还怀疑您从服务器发送的ping会使会话显示为活动状态,因此对空闲会话超时配置没有帮助

    至于为什么Tomcat没有更早地意识到客户端断开了连接,我真的不能说。根据我的经验,如果客户端关闭WebSocket连接,或者如果我关闭浏览器,就会立即检测到它。无论如何,这与Tomcat有关,而不是与Spring有关