代码之家  ›  专栏  ›  技术社区  ›  cstack

Spring Websocket服务器在发送大量数据时重置连接

  •  1
  • cstack  · 技术社区  · 7 年前

    我遇到了这样的问题:当尝试从Spring Websocket服务器(托管在Tomcat上)发送数据时,似乎在尝试发送消息的过程中重置了连接。在发送大量二进制数据(本例中为5526584字节)时,错误似乎发生得更多,但我已经看到它发生在文本通道上,并且数据也更少。然而,发送超过5 MB左右的数据似乎会相对一致地导致崩溃。

    WebSocketContainer c = ContainerProvider.getWebSocketContainer();
    
    
        c.setDefaultMaxTextMessageBufferSize(128000000); // Should we enable these on the client?
        c.setDefaultMaxBinaryMessageBufferSize(128000000); // Should we enable these on the client?
        c.setDefaultMaxSessionIdleTimeout(500000);
        c.setAsyncSendTimeout(50000);
        session = c.connectToServer(this, config, new URI("wss://" + SERVER + ":" + PORT + WEBSOCKETENDPOINT));
    

    我稍后打印出会话MaxBuffer大小,它们都按预期设置为128000000。

    结束编辑

    java.io.IOException: An established connection was aborted by the software in your host machine
    at sun.nio.ch.SocketDispatcher.write0(Native Method)
    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
    at sun.nio.ch.IOUtil.write(IOUtil.java:65)
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
    at org.apache.tomcat.util.net.SecureNioChannel.flush(SecureNioChannel.java:143)
    at org.apache.tomcat.util.net.SecureNioChannel.close(SecureNioChannel.java:494)
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.close(NioEndpoint.java:1201)
    at org.apache.tomcat.websocket.server.WsRemoteEndpointImplServer.doClose(WsRemoteEndpointImplServer.java:167)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.close(WsRemoteEndpointImplBase.java:710)
    at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:599)
    at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:480)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:313)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:258)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendPartialBytes(WsRemoteEndpointImplBase.java:161)
    at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendBinary(WsRemoteEndpointBasic.java:56)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketSession.sendBinaryMessage(StandardWebSocketSession.java:202)
    at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:107)
    at org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator.tryFlushMessageBuffer(ConcurrentWebSocketSessionDecorator.java:132)
    at org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator.sendMessage(ConcurrentWebSocketSessionDecorator.java:104)
    at myHandlerpart2.handleBinaryMessage(myHandlerpart2.java:252)
    at myHandler.handleMessageFromClient(myHandler.java:200)
    at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:307)
    at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75)
    at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56)
    at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:58)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleBinaryMessage(StandardWebSocketHandlerAdapter.java:120)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$100(StandardWebSocketHandlerAdapter.java:42)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$4.onMessage(StandardWebSocketHandlerAdapter.java:87)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$4.onMessage(StandardWebSocketHandlerAdapter.java:84)
    at org.apache.tomcat.websocket.WsFrameBase.sendMessageBinary(WsFrameBase.java:576)
    at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageBinary(WsFrameServer.java:122)
    at org.apache.tomcat.websocket.WsFrameBase.processDataBinary(WsFrameBase.java:535)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:127)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:73)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148)
    at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
    

    public ServletServerContainerFactoryBean createWebSocketContainer() {
    
    ServletServerContainerFactoryBean container = new 
    ServletServerContainerFactoryBean();
    container.setMaxTextMessageBufferSize(128000000); //128 MB
    container.setMaxBinaryMessageBufferSize(128000000); //128 MB
    container.setMaxSessionIdleTimeout(500000);
    container.setAsyncSendTimeout(50000);
    
    return container;
    }
    

    我还为subtoclhandler设置了限制

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    
    
        SubProtocolWebSocketHandler test = new SubProtocolWebSocketHandler(new DirectChannel(), clientInboundChannel());
        test.setSendBufferSizeLimit(128000000);
        test.setSendTimeLimit(50000);
        for(SubProtocolHandler handler : handlers)
        {
            test.addProtocolHandler(handler);
        }
    
    
        MyWebSocketHandshakeHandler handshaker = new MyWebSocketHandshakeHandler();
    
    
        handshaker.setSupportedProtocols(test.getSubProtocols().toArray(new String[0]));
        registry.addHandler(test, websocketEndpoint).setHandshakeHandler(handshaker)
                .addInterceptors(new HttpSessionHandshakeInterceptor()).setAllowedOrigins("*");
    
    }
    

    最后,导致错误的实际发送如下所示

    byte[] tbuf = null;
            try {
                tbuf = jsonMapper.writeValueAsBytes(demoLists.get(stage));
                ByteBuffer buf = ByteBuffer.allocate(tbuf.length);
                buf.put(tbuf);
                buf.flip();
                WebSocketMessage<ByteBuffer> ret = new BinaryMessage(buf);
                System.out.println("Binary limit: " + session.getBinaryMessageSizeLimit());
                System.out.println("Sending bytes: " + ret.getPayloadLength());
                if(session.isOpen()) {
                    session.sendMessage(ret);
    
                } else {
                    System.out.println("Session is closed already.");
                }
    

    代码中有很多移动部分,因此如果您需要任何其他信息,请告诉我。

    1 回复  |  直到 7 年前
        1
  •  2
  •   cstack    7 年前

    在做了更多的研究之后,我发现了这个问题 Incoming buffer size cannot be set to Tyrus client 这让我想到 https://tyrus-project.github.io/documentation/1.12/user-guide.html#d0e1197

    ClientManager client = ClientManager.createClient(c); 
        client.getProperties().put("org.glassfish.tyrus.incomingBufferSize", 128000000); 
        session = client.connectToServer(this, config, new URI("wss://" + SERVER + ":" + PORT + WEBSOCKETENDPOINT));
    
    推荐文章