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



我有一个实时应用程序,其客户端使用websocket与运行Spring Boot Tomcat的Spring Framework服务器连接。我希望服务器能够快速(在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;
    }
    

我不确定这是否正确实现,因为我没有看到Servlet ServerContainerFactoryBean和我生成的ClientHandlers之间的链接。

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

  2. 1和2同时

  3. 1和2以及在application.properties 中设置server.session-timeout = 5

我的测试方法是:

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

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

应用程序事件可能会对您有所帮助。

PS:注释驱动的事件

PS2:我为您做了一个示例项目

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

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

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

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

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

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

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

由于这个问题和投票最多的答案都很老了,我们想添加最简单的方法来实现spring-websocket实现。

参见第4.4.8节。简单经纪人

@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);
        // ...
    }
}

当返回连接响应帧时,websocket服务器需要发送hearbeat参数以从客户端启用ping。

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

相关内容

  • 没有找到相关文章

最新更新