如何在Java Spring Tomcat中快速关闭无响应的websocket?

我有一个实时应用程序,客户端使用websockets连接Spring Framework服务器,该服务器运行Spring Boot Tomcat。 我希望服务器能够快速(在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,并在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连接中使用超时应该有一种更简单的方法来实现它。