Spring-Websockets 4.2 中使用 SockJS 的部分消息

Posted

技术标签:

【中文标题】Spring-Websockets 4.2 中使用 SockJS 的部分消息【英文标题】:Partial messages with SockJS in Spring-Websockets 4.2 【发布时间】:2016-01-27 02:09:33 【问题描述】:

我正在使用带有 SockJS 的 Spring-Websockets 4.2。

由于客户端收到的消息可能很大,我想使用部分消息。我的 TextWebSocketHandler 子类确实覆盖了supportsPartialMessages 以返回true。但是,由于 Spring 创建的 SockJsWebSocketHandler 不支持部分消息,我仍然收到错误code=1009, reason=The decoded text message was too big for the output buffer and the endpoint does not support partial messages

作为一种解决方法,我已将缓冲区大小增加到 1 MB,如 here 所述,但由于我必须支持大量客户端(同时大约 2000 个),这需要太多内存.

有没有办法在 SockJS 中使用部分消息?

【问题讨论】:

你能解决这个问题吗?我也面临同样的问题,一直没有找到解决办法?还有container.setMaxTextMessageBufferSize(16384) 中提到的数字,是位、字节、kbs 还是什么? 不,很遗憾没有。我们最终通过在发送者处分块并在接收者处重新组装来实现部分消息传递。 setMaxTextMessageBufferSize 以字节为单位 AFAIK。 您能使用粘性会话式负载均衡器来拆分消息吗?听起来您几乎需要实现反应式流或在常规套接字之外使用适当的横向扩展消息队列来处理您的消息。 @Jan 你能分享一些细节你是怎么做到的吗?您是否使用了WebSocketHandlerDecorator 或更多的应用程序级别?客户呢? 我无法再访问代码,但如果我没记错的话,我最终会在应用层处理这一切。类似于将整个消息包装在 JSON 对象中,手动将其拆分为 1MB 块,然后在接收方进行缓冲,直到最终的 '' 到达。 【参考方案1】:

就我而言,我的 tomcat 服务器使用 TextWebSocketHandler。 在这样做之前,你需要检查一下,supportsPartialMessages。

首先,如下覆盖supportsPartialMessages()

//This value set as true in my properties file. Just for test. actually you don't need this.
@Value("#config['server.supportsPartialMessages']")
private boolean supportsPartialMessages;

//If you need to handle partial message, should return true.
@Override
public boolean supportsPartialMessages() 
    return supportsPartialMessages;     

然后我添加“messageRoom”属性以在建立连接时将部分消息存储到每个 websocket 会话。

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception 
    super.afterConnectionEstablished(session);

    //I think this is easier to keep each message and each client.
    session.getAttributes().put("messageRoom", new StringBuilder(session.getTextMessageSizeLimit()));

当您从客户端收到消息时,请执行此操作。

@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception 
    super.handleTextMessage(session, message);

    StringBuilder sbTemp = (StringBuilder)session.getAttributes().get("messageRoom");

    //isLast() will tell you this is last chunk or not.
    if(message.isLast() == false)      
        sbTemp.append(Payload);

    else 
        if(sbTemp.length() != 0)           
            sbTemp.append(Payload);     

            this.logger.info(session.getRemoteAddress() + ":RECEIVE_TO[CLIENT][PARTIAL][" + sbTemp.length() + "]:" + sbTemp.toString());
            doYourWork(session, sbTemp.toString());
            //Release memory would be nice.
            sbTemp.setLength(0);
            sbTemp.trimToSize();

        else          
            this.logger.info(session.getRemoteAddress() + ":RECEIVE_TO[CLIENT][WHOLE]:" + message.getPayload());
            doYourWork(session, Payload);
        
    

这是几年前做的,所以我不记得我从哪里得到的。 但我还是很感激他们。

【讨论】:

以上是关于Spring-Websockets 4.2 中使用 SockJS 的部分消息的主要内容,如果未能解决你的问题,请参考以下文章

如何告诉 Spring Boot 忽略 Jetty 并始终使用 Tomcat?

如何在 FreeBSD 9.1 系统中使用 libdb-4.2?

如何在 Smack 4.2 中使用证书

在 extjs4.1 和 4.2 中使用 CheckboxModel 删除和添加 Gridpanel 再次失败

Swift 4.2 - 如何在枚举函数中使用警报?

skia项目运行在Android.4.2,Android 4.2和Android 2.2有区别吗?