如何将二进制消息作为输入流处理?

Posted

技术标签:

【中文标题】如何将二进制消息作为输入流处理?【英文标题】:How to process binary messages as input streams? 【发布时间】:2019-10-15 13:06:59 【问题描述】:

我想通过 WebSockets 实现大文件的上传,并让服务器将文件存储在数据库或对象存储中。

我正在试用spring-websocket 库,据我了解,我需要扩展BinaryWebSocketHandler 类并在那里实现文件存储。

public class MyWebSocketHandler extends BinaryWebSocketHandler 

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception 
          // Store file in DB/OS...
    


虽然这看起来很棒,但我的问题是我要处理的 BinaryMessage 只允许我使用 ByteBuffers。我假设这意味着整个文件被加载到内存中并存储在这个ByteBuffer 对象中(当然,除非我也覆盖了supportsPartialMessages 方法)。这是正确的吗?

如果是,这对我来说将是一个大问题,因为我不想在内存中存储大文件。我期待能够访问InputStream 并从那里读取文件。看起来这应该是可能的,因为spring-websocket 在后台使用 Java WebSocket API,并且它们允许MessageHandlers 处理InputStreams(请参阅https://docs.oracle.com/javaee/7/api/javax/websocket/MessageHandler.Whole.html)。

不幸的是,我在我的处理程序中找不到任何访问InputStream 的方法。有谁知道这是否真的可能?如果不是,这作为功能请求是否有意义,或者这是否会以某种方式滥用 WebSockets?

【问题讨论】:

【参考方案1】:

您可以覆盖AbstractWebSocketHandler.supportsPartialMessages,它声明:

如果此标志设置为 true 并且底层 WebSocket 服务器支持部分消息,则可能会拆分大型 WebSocket 消息或未知大小的消息之一,并可能通过对 WebSocketHandler.handleMessage(WebSocketSession, WebSocketMessage) 的多次调用来接收。标志 WebSocketMessage.isLast() 指示消息是否为部分以及是否为最后部分。

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/socket/WebSocketHandler.html

【讨论】:

我知道部分消息,但如果我使用这些消息,将文件保存在数据库或对象存储中会变得更加困难。当我收到块 #1 时,我可以轻松地将其插入数据库,但是当它出现时我将如何附加块 #2?我不知道有任何与数据库无关的 SQL 语句可以让我这样做。这就是为什么我想使用 InputStream 而不是字节数组。 您可能希望写入一个临时文件,而不是写入数据库,然后在isLast 上将该文件插入数据库。另请参阅:***.com/questions/37896551/… 一个我没有看到解决的问题是放弃转移。 我希望避免这种情况,因为我的应用程序在磁盘空间有限的容器中运行,因此如果同时触发大量上传,使用临时文件可能会导致崩溃。使用 Spring WebMVC 和 HTTP,我可以访问 InputStream 并将其直接传递给数据库。我希望 Web 套接字也能实现同样的目标,但显然情况并非如此。我将尝试在他们的 GitHub 页面中打开一个功能请求。也许是有原因的。感谢您向我指出相关问题。显然,其他人也对此感兴趣。 也许仅依靠 WebMVC / HTTP 进行此类上传是值得的,例如,通过套接字的消息可以“请求”一个端口和上传文件的权限,然后单独处理。通过链接这两者,您可以直接将 websocket 会话与文件相关联,并坚持使用 websocket 处理其他所有内容。 我实际上想要相反 - 使用 Web 套接字进行文件上传,使用 HTTP 进行其他所有操作。在请求到达我的应用程序之前,它会通过一个路由器应用程序(即 Cloud Foundry 的 GoRouter)。此路由器会终止在 15 分钟内未收到响应的每个请求,如果上传文件很大和/或用户的 Internet 连接速度较慢,则很容易发生这种情况。但是,路由器不会终止 Web 套接字通信(至少据我所知)。

以上是关于如何将二进制消息作为输入流处理?的主要内容,如果未能解决你的问题,请参考以下文章

12.4 处理流的用法

IO流07_输入输出流总体系

如何使用张量流数据集 (TDFS) 作为张量流模型的输入?

处理成功后如何删除redis流

Spring Boot 之 Kafka

阿里云消息队列 RocketMQ 5.0 全新升级:消息事件流融合处理平台