当前位置: 首页 > 知识库问答 >
问题:

用Spring boot后端践踏sockjs角5客户端,每个生命周期随机断开一次连接

宋鸿云
2023-03-14

我有一个角5客户端连接到使用sockjs跺p的Spring启动后端。它工作正常,只是每个“客户端连接生命周期”客户端随机(大约20-30秒后)失去与后端的套接字连接。在错误回调中再次调用connect(...)函数后,套接字连接在运行时的剩余时间内保持不变。

这种行为在最新版本的Chrome和Firefox上都是一样的。

angular客户端对stomp和socketjs具有以下依赖关系:

"sockjs": "^0.3.19",
"stompjs": "^2.3.3",

这是如何在客户端管理连接:

private sockAddress: string = '/websocket';
private socket;
private stompClient;
private subscriptions: [string, (message: String) => void][];
...
connect() {
    const headers = {};
    this.socket = new SockJS(this.sockAddress);
    this.stompClient = Stomp.over(this.socket);
    this.stompClient.heartbeat.incoming = 1000;
    this.stompClient.heartbeat.outgoing = 1000;
    this.stompClient.connect(headers, this.connectCallback.bind(this), this.errorCallback.bind(this));
  }

connectCallback(frame): void {
    // called back after the client is connected and authenticated to the STOMP server
    this.isConnected = true;

    for (let subscription of this.subscriptions) {
      this.subscribeToEndpoint(subscription[0], subscription[1]);
    }
  }

errorCallback(): void {
    console.log('error callback called, socket not connected!');
    this.isConnected = false;
    // reconnecting
    this.connect();
  }

sendMessage(message: string, endpoint: string): void {
    if (this.stompClient != null && this.isConnected) {
      this.stompClient.send(endpoint, {}, message);
    } else {
      console.log('socket not connected');
    }
  }

private subscribeToEndpoint(endpoint: string, callback: (message: String) => void) {
    if (this.isConnected == true) {
      this.stompClient.subscribe(endpoint, callback);
    }
  }

这是配置的相关服务器端部分:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        ThreadPoolTaskScheduler te = new ThreadPoolTaskScheduler();
        te.setPoolSize(2);
        te.setThreadNamePrefix("wss-heartbeat-thread-");
        te.initialize();
        config.enableSimpleBroker("/data").setTaskScheduler(te).setHeartbeatValue(new long[]{1000, 1000});
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/websocket").withSockJS();
    }
}

以及如何处理消息:

@MessageMapping("/element/create")
@SendTo("/data/element/created")
public ApprovedElementDTO createElement(CreateElementDTO element) {
    LOG.debug("createElement called: " + element.getType().toString());
    return this.socketService.approveElementId(element);
}

用于套接字的相关maven依赖项:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
        <version>1.5.9.RELEASE</version>
    </dependency>

客户端上的错误消息如下所示:

zone.js:2933 POST http://localhost:4200/websocket/461/1uzrn1r4/xhr_send?    t=1513249327232 404 (Not Found)
scheduleTask @ zone.js:2933
ZoneDelegate.scheduleTask @ zone.js:411
onScheduleTask @ zone.js:301
ZoneDelegate.scheduleTask @ zone.js:405
Zone.scheduleTask @ zone.js:236
Zone.scheduleMacroTask @ zone.js:259
(anonymous) @ zone.js:2966
proto.(anonymous function) @ zone.js:1366
AbstractXHRObject._start @ abstract-xhr.js:132
(anonymous) @ abstract-xhr.js:21
ZoneDelegate.invokeTask @ zone.js:425
onInvokeTask @ core.js:4621
ZoneDelegate.invokeTask @ zone.js:424
Zone.runTask @ zone.js:192
ZoneTask.invokeTask @ zone.js:499
ZoneTask.invoke @ zone.js:488
timer @ zone.js:2040
setTimeout (async)
scheduleTask @ zone.js:2056
ZoneDelegate.scheduleTask @ zone.js:411
onScheduleTask @ zone.js:301
ZoneDelegate.scheduleTask @ zone.js:405
Zone.scheduleTask @ zone.js:236
Zone.scheduleMacroTask @ zone.js:259
(anonymous) @ zone.js:2072
proto.(anonymous function) @ zone.js:1366
AbstractXHRObject @ abstract-xhr.js:20
XHRCorsObject @ xhr-cors.js:8
(anonymous) @ ajax-based.js:21
BufferedSender.sendSchedule @ buffered-sender.js:59
BufferedSender.send @ buffered-sender.js:26
SockJS.send @ main.js:163
Client._transmit @ stomp.js:159
Client.send @ stomp.js:366
SocketService.sendMessage @ socket.service.ts:79
ElementTransmission.sendElementCreationEvent @ ElementTransmission.ts:56
PluginHandler.sendElementCreationEvent @ PluginHandler.ts:266
DiagramComponent.onClick @ diagram.component.ts:150
dispatch @ scripts.bundle.js:4
q.handle @ scripts.bundle.js:4
ZoneDelegate.invokeTask @ zone.js:425
onInvokeTask @ core.js:4621
ZoneDelegate.invokeTask @ zone.js:424
Zone.runTask @ zone.js:192
ZoneTask.invokeTask @ zone.js:499
invokeTask @ zone.js:1540
globalZoneAwareCallback @ zone.js:1566
stomp.js:134 Whoops! Lost connection to http://localhost:4200/websocket

有时我也会随机收到此错误消息,但对连接没有任何影响:

VM3454:164 WebSocket connection to 'ws://localhost:4200/websocket/954/i52geoxw/websocket' failed: Connection closed before receiving a handshake response
WrappedWebSocket @ VM3454:164
WebSocketBrowserDriver @ websocket.js:6
WebSocketTransport @ websocket.js:32
SockJS._connect @ main.js:219
SockJS._receiveInfo @ main.js:193
g @ emitter.js:30
EventEmitter.emit @ emitter.js:50
(anonymous) @ info-receiver.js:67
g @ emitter.js:30
EventEmitter.emit @ emitter.js:50
(anonymous) @ info-ajax.js:37
g @ emitter.js:30
EventEmitter.emit @ emitter.js:50
xhr.onreadystatechange @ abstract-xhr.js:124
wrapFn @ zone.js:1166
ZoneDelegate.invokeTask @ zone.js:425
onInvokeTask @ core.js:4621
ZoneDelegate.invokeTask @ zone.js:424
Zone.runTask @ zone.js:192
ZoneTask.invokeTask @ zone.js:499
invokeTask @ zone.js:1540
globalZoneAwareCallback @ zone.js:1566

在Spring boot后端,当连接丢失时,我会遇到以下异常,这与我通过简单地关闭浏览器选项卡来终止客户端时是一样的。

2017-12-14 12:02:09.507  INFO 16672 --- [tboundChannel-6] o.apache.coyote.http11.Http11Processor   : An error occurred in processing while on a non-container thread. The connection will be closed immediately

java.io.IOException: Eine bestehende Verbindung wurde softwaregesteuert
durch den Hostcomputer abgebrochen
    at sun.nio.ch.SocketDispatcher.write0(Native Method) ~[na:1.8.0_152]
    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51) ~[na:1.8.0_152]
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93) ~[na:1.8.0_152]
    at sun.nio.ch.IOUtil.write(IOUtil.java:65) ~[na:1.8.0_152]
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471) ~[na:1.8.0_152]
    at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:134) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:157) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1221) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.util.net.SocketWrapperBase.flushBlocking(SocketWrapperBase.java:451) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.util.net.SocketWrapperBase.flush(SocketWrapperBase.java:441) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.http11.Http11OutputBuffer.flushBuffer(Http11OutputBuffer.java:514) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.http11.Http11OutputBuffer.flush(Http11OutputBuffer.java:243) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.http11.Http11Processor.flush(Http11Processor.java:1495) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:284) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.Response.action(Response.java:167) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:336) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:303) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.connector.Response.flushBuffer(Response.java:541) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.connector.ResponseFacade.flushBuffer(ResponseFacade.java:312) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at javax.servlet.ServletResponseWrapper.flushBuffer(ServletResponseWrapper.java:176) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at javax.servlet.ServletResponseWrapper.flushBuffer(ServletResponseWrapper.java:176) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.security.web.util.OnCommittedResponseWrapper.flushBuffer(OnCommittedResponseWrapper.java:158) [spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    at javax.servlet.ServletResponseWrapper.flushBuffer(ServletResponseWrapper.java:176) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.security.web.util.OnCommittedResponseWrapper.flushBuffer(OnCommittedResponseWrapper.java:158) [spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    at org.springframework.http.server.ServletServerHttpResponse.flush(ServletServerHttpResponse.java:96) [spring-web-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.writeFrameInternal(AbstractHttpSockJsSession.java:350) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.writeFrame(AbstractSockJsSession.java:322) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.sockjs.transport.session.StreamingSockJsSession.flushCache(StreamingSockJsSession.java:86) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.sendMessageInternal(AbstractHttpSockJsSession.java:290) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.sendMessage(AbstractSockJsSession.java:166) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator.tryFlushMessageBuffer(ConcurrentWebSocketSessionDecorator.java:132) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator.sendMessage(ConcurrentWebSocketSessionDecorator.java:104) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.messaging.StompSubProtocolHandler.sendToClient(StompSubProtocolHandler.java:439) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageToClient(StompSubProtocolHandler.java:426) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:338) [spring-websocket-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) [spring-messaging-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_152]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_152]
    at java.lang.Thread.run

(Thread.java:748) [na:1.8.0_152]

你对我的代码中可能出现的错误有什么建议吗?是什么导致了这些连接中断?这对我来说是一个严重的问题,因为在重新连接期间发送数据包当然不起作用。此外,只有当我(或心跳)尝试发送数据包时,才会调用错误回调。

共有1个答案

贾飞章
2023-03-14

在我的例子中,这是问题的根源,没有为WebSocket正确配置代理,代理中的以下条目。conf.json修复了它:“/websocket”:{“target”:“localhost:8080”,“secure”:false,“logLevel”:“warn”,“ws”:true}其中缺少“ws”:true部分。

 类似资料:
  • 大家好,我是EJB组件技术的新手,为了准备我的学术讨论会考试,我必须学习这一点。我不确定我能理解生命周期的所有细节。 -客户机对EJB容器的请求(但该请求如何完成?请求的位置我指的是远程“EJB容器外部”还是本地“EJB容器内部”重要与否?) -根据请求,在池中创建一个bean实例并返回给客户机,在从客户机使用后,它再次返回池中(取决于bean类型(?))。 我认为这个场景适合于无状态会话bean

  • 阅读了ApacheHTTP组件模块的连接管理文档,以及关于连接保持活动策略和连接退出策略的其他一些资源后,我感到非常困惑。 其中有很多形容词用来描述连接的状态,比如,,,和等。没有一个生命周期图来描述连接在这些状态之间的变化。 我的困惑主要来自以下情况。 我通过下面的代码片段设置了一个,它提供了5秒的。 与我交谈的服务器确实支持保持连接的活动状态。当我在一个批处理中异步执行大约200个请求后打印出

  • 问题内容: 我使用和创建一个实时Web应用程序。我将为用户提供对套接字连接的完全控制,例如手动断开连接和(重新)连接。 在客户端启动时,该功能可以正常运行,但是在使用之后,不会启动新连接。 问题答案: 现在可以使用socket.socket.reconnect() 相关:https : //github.com/LearnBoost/socket.io- client/issues/251

  • 我使用java ssh客户端(http://www.jcraft.com/jsch/)连接到远程机器并执行命令。代码工作正常,直到我连接到远程机器并执行命令。然而,问题是,即使命令执行成功,通道和会话也不会断开。 我也打电话给session.disconnect和channel.disconnect,但仍然是问题所在。 这是我的代码: 请建议

  • 我正在使用C#window应用程序表单对TCP多线程服务器进行工作,我正在尝试检测客户端的机器是否关闭并断开与服务器的连接。看了一些帖子,有了一些想法: 如何确定tcp是否连接? 我的代码如下: 多谢帮忙。

  • 编辑2:我切换到,并用包装客户端工厂,这样设备就可以很好地到达后端。但是当后端发回一些东西时,我会得到错误的出站套接字,客户机套接字死亡。我认为这是因为后端没有正确路由消息所必需的头。如何捕获此信息?我的配置类如下: