基于 Spring Boot 的 WebSocket 服务器在格式错误的数据包后变得无响应 [英] WebSocket server based on Spring Boot becomes unresponsive after a malformed packet

查看:27
本文介绍了基于 Spring Boot 的 WebSocket 服务器在格式错误的数据包后变得无响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基于 Spring Boot 1.5.9.RELEASE 的普通 WebSocket 应用程序.

I have a trivial WebSocket application based on Spring Boot 1.5.9.RELEASE.

SocketHandler.java:

SocketHandler.java:

import org.springframework.stereotype.Component; 
import org.springframework.web.socket.TextMessage; 
import org.springframework.web.socket.WebSocketSession; 
import org.springframework.web.socket.handler.TextWebSocketHandler; 
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.List;
import java.io.IOException;

@Component 
public class SocketHandler extends TextWebSocketHandler { 

    List<WebSocketSession> sessions = new CopyOnWriteArrayList<WebSocketSession>();

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message)
            throws InterruptedException, IOException {
        for(WebSocketSession webSocketSession : sessions) {
            webSocketSession.sendMessage(message);
        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //the messages will be broadcasted to all users.
        sessions.add(session);
    }
}

WebSocketConfig.java:

WebSocketConfig.java:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket 
public class WebSocketConfig implements WebSocketConfigurer { 
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { 
        registry.addHandler(new SocketHandler(), "/name");
    }
}

Main.java:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

我使用嵌入式 Tomcat 服务器.

I use the embedded Tomcat server.

当我从一个简单的 HTML/JavaScript 页面访问应用程序时,它工作得很好.但是当我尝试原生 WebSocket 实现(cwebsocket)时,整个服务器在第一个请求后变得无响应.第一个请求成功通过,但最后有这个异常:

It works great when I access the application from a simple HTML/JavaScript page. But when I try a native WebSocket implementation (cwebsocket), the whole server becomes unresponsive after the first request. The first request goes through successfully but at the end there is this exception:

018-01-18 11:32:44.666 ERROR 12567 --- [nio-8080-exec-3] w.s.h.ExceptionWebSocketHandlerDecorator : Closing session due to exception for StandardWebSocketSession[id=1, uri=/name]

java.lang.IllegalStateException: The WebSocket session [0] has been closed and no method (apart from close()) may be called on a closed session
        at org.apache.tomcat.websocket.WsSession.checkState(WsSession.java:806) ~[tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.WsSession.getBasicRemote(WsSession.java:432) ~[tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.springframework.web.socket.adapter.standard.StandardWebSocketSession.sendTextMessage(StandardWebSocketSession.java:203) ~[spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:101) ~[spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at com.wattsense.service.prototype.websocket.SocketHandler.handleTextMessage(SocketHandler.java:20) ~[main/:na]
        at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43) ~[spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) ~[spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) ~[spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:58) ~[spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:110) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:81) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:78) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
        at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:395) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:495) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
        at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) [tomcat-embed-core-8.5.23.jar:8.5.23]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-8.5.23.jar:8.5.23]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.23.jar:8.5.23]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.23.jar:8.5.23]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.23.jar:8.5.23]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.23.jar:8.5.23]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]

显然,cwebsocket 在会话结束时发送了一个格式错误的数据包.

Obviously, cwebsocket is sending a malformed packet at the end of the session.

但是没有任何作用,没有提供 WebSocket 请求,也没有抛出进一步的异常.嵌入式 Tomcat 的普通 Web 服务器部分可以工作,它为 HTML/JavaScript 应用程序提供服务,但该应用程序也无法打开 WebSocket 连接.

But then nothing works, no WebSocket request is served and no further exception is thrown. The normal web server part of the embedded Tomcat works, it serves the HTML/JavaScript application but that application can't open a WebSocket connection either.

很明显,cwebsocket 有问题,但这不是我关心的.我更担心整个服务器因为客户端故障而宕机.任何人都有想法,如何解决这个问题?

Clearly, there is a problem in cwebsocket but it is not my concern. I am more concerned by the fact that the whole server goes down because of a faulty client. Anyone has an idea, how to fix this?

我试过TLS/SSL配置和Spring Boot 2.0.0.M7,症状是一样的.

I have tried TLS/SSL configuration and Spring Boot 2.0.0.M7, the symptoms are the same.

推荐答案

我终于有了一个有效的解决方案.从上面的堆栈跟踪中可以看出,WebSocketSession.sendMessage 方法抛出了一个异常.最初的实现没有处理这个异常,而是让它冒泡了.因为作为 WebSocketHandler 解释:鼓励此接口的实现在有意义的情况下在本地处理异常,或者让异常冒泡,在这种情况下,默认情况下会记录异常并使用 SERVER_ERROR(1011) 关闭会话.

At last I have a solution that works. As can be seen in the stack trace above, there's an exception thrown from the WebSocketSession.sendMessage method. The original implementation did not handle this exception but let it bubble up. Because as WebSocketHandler explains: Implementations of this interface are encouraged to handle exceptions locally where it makes sense or alternatively let the exception bubble up in which case by default the exception is logged and the session closed with SERVER_ERROR(1011).

冒泡异常出了点问题,因为它杀死了整个 websocket 服务器.

Something went very wrong with bubbling up the exception because it killed the whole websocket server.

解决办法:<代码>

            try {
                webSocketSession.sendMessage(message);
            } catch( Exception ex ) {
                LOGGER.log( Level.SEVERE,"handleTextMessage",ex );
                synchronized( sessions ) {
                    sessions.remove( webSocketSession );
                }
            }

这篇关于基于 Spring Boot 的 WebSocket 服务器在格式错误的数据包后变得无响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆