我有一个基于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,症状是一样的。
答案 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 下面还有一些评论