在格式错误的数据包

时间:2018-01-18 11:08:46

标签: tomcat spring-boot websocket

我有一个基于Spring Boot 1.5.9.RELEASE的简单WebSocket应用程序。

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:

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服务器。

从简单的HTML / JavaScript页面访问应用程序时效果很好。但是,当我尝试本机WebSocket实现(cwebsocket)时,整个服务器在第一次请求后变得无响应。第一个请求成功完成,但最后有一个例外:

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在会话结束时发送格式错误的数据包。

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

显然,cwebsocket存在问题,但这不是我关注的问题。我更担心整个服务器由于客户端故障而关闭。任何人都有一个想法,如何解决这个问题?

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

2 个答案:

答案 0 :(得分:1)

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

冒泡异常是非常错误的,因为它杀死了整个websocket服务器。

解决方案: self.tableView.beginUpdates() self.tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic) self.tableView.endUpdates()

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

答案 1 :(得分:0)

是的, 我遇到了同样的问题。 在启动/停止前端/集成测试时,我一直在运行后端

根本原因是,如果客户端删除会话,会话将保留在后端 在列表会话中 防御方法之一是您提出的,另一种更为优雅的方法是

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    sessions.remove(session);
}

btw:我想上面的代码来自 https://www.devglan.com/spring-boot/spring-websocket-integration-example-without-stomp 下面还有一些评论

相关问题