【问题标题】:MTOM Not Writing Data in ChunksMTOM 未在块中写入数据
【发布时间】:2016-03-25 00:46:39
【问题描述】:

我们有一个用例,我们必须通过 http 将大型数据文件从环境 A 传输到环境 B。我们想要实现的是发送方以块的形式发送数据,而接收者开始以块的形式将其写入文件中。因此我们决定使用 MTOM。

网络服务代码:

@MTOM(enabled = true, threshold=1024)
@WebService(portName = "fileUploadPort", endpointInterface = "com.cloud.receiver.FileUploadService", serviceName = "FileUploadService")
@BindingType(value = SOAPBinding.SOAP12HTTP_MTOM_BINDING)
public class FileUploadServiceImpl implements FileUploadService {

@Override
public void uploadFile(FileUploader Dfile) {

    DataHandler handler = Dfile.getFile();
    try {
        InputStream is = handler.getInputStream();

        OutputStream os = new FileOutputStream(new File(absolutePath));
        byte[] b = new byte[10000000];
        int bytesRead = 0;
        while ((bytesRead = is.read(b)) != -1) {
            os.write(b, 0, bytesRead);
        }
        os.flush();
        os.close();
        is.close();

    } catch (IOException e) {
        e.printStackTrace();
    }

}
}

客户代码:

public static void main(String args[]) throws Exception {

    URL url = new URL("http://localhost:8080/CloudReceiver/FileUploadService?wsdl");

    QName qname = new QName("http://receiver.cloud.com/", "FileUploadService");

    Service service = Service.create(url, qname);
    FileUploadService port = service.getPort(FileUploadService.class);
    // enable MTOM in client
    BindingProvider bp = (BindingProvider) port;
    SOAPBinding binding = (SOAPBinding) bp.getBinding();
    binding.setMTOMEnabled(true);

    FileUploader f = new FileUploader();
    DataSource source = new FileDataSource(new File("G:\\Data\\Sender\\temp.csv"));
    DataHandler dh = new DataHandler(source);
    Map<String, Object> ctxt = ((BindingProvider) port).getRequestContext();
    // Marking Chunk size at Client.
    ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 100);

    f.setFile(dh);
    port.uploadFile(f);
}

当我们传输小于 100MB 的数据时,一切正常。 超过 (100MB+) 应用服务器 (JBoss 8.2) 的数据文件在接收器端抛出以下异常。

java.io.IOException: UT000020: Connection terminated as request was larger than 104857600

我知道这个错误是因为standalone.xml中的属性

<http-listener name="default" socket-binding="http" max-post-size="104857600"/>

这意味着数据不会写入块中的文件,而是保存在内存中,然后在传输完成后写入文件。

我们如何实现将数据写入块中的文件?我们不希望帖子内存增加。文件大小可以达到 1 TB。

环境: JBoss 8.2 野飞,Java 8

【问题讨论】:

  • 嗨,我通过为字节数组切片文件并循环发送数组解决了这个问题,我认为客户端在单个请求中将所有通道发送到服务器。
  • 如果我们必须对文件进行切片,那么 MTOM 需要什么?我觉得 MTOM 应该处理切片......切片在客户端代码中得到了很好的照顾......
  • 可以添加FileUploadService的代码吗?
  • 您好,如果您对其中一个答案感到满意,您介意“接受”它吗?这将有助于社区,尤其是奖励那些帮助你的人。谢谢。

标签: java file jboss nio mtom


【解决方案1】:

首先,提到的限制

<http-listener name="default" socket-binding="http" max-post-size="104857600"/>

表示服务器接受的整个 POST 请求的最大大小。

无论是否使用了 MTOM,是否使用了块 - 您在此处发送的文件仅包含一个 POST 请求。使用块不会改变这一点 - 所有带有文件数据的块都是同一个 POST 请求的一部分。

所以它按预期工作:100M+ 文件太大了,相应的限制。

那么,我很确定这个结论

这意味着数据不会写入块中的文件,而是保存在内存中,然后在传输完成后写入文件。

完全是错误的。将潜在的大卷保存在内存中并不安全,因此服务器通常不会这样做,而是将这些卷放入一些临时文件中。

【讨论】:

    【解决方案2】:

    一些解释

    Sudeep:这意味着数据不会写入块中的文件,而是保存在内存中,然后在传输完成后写入文件。

    --> 这绝对不是真的。

    以下限制:

    <http-listener name="default" socket-binding="http" max-post-size="104857600"/>
    

    .. 表示单个(最终分块的)POST 请求的最大正文大小不能超过 104857600 字节。这与 HTTP content-length 标头和 JBoss 自身功能(如缓冲区)的配置有关。

    参照。 https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.htmlThe Content-Length entity-header field indicates the size of the entity-body, in decimal number of OCTETs, sent to the recipient or, in the case of the HEAD method, the size of the entity-body that would have been sent had the request been a GET.

    我建议执行 Wireshark 分析以说服自己。

    .


    Sudeep:我们想要实现的是发送方将数据分块发送,而接收方开始将数据分块写入文件。因此我们 决定使用 MTOM。

    --> 我认为这是一个错误的决定。

    首先

    MTOM 并不是专门为分块数据而设计的SOAP Message Transmission Optimization Mechanism (MTOM)主要定义了两个优化:

    • 一种抽象功能,通过选择性地编码消息的各个部分来优化 SOAP 消息的传输和/或有线格式,同时仍向 SOAP 应用程序呈现 XML 信息集。
    • 一种优化的 MIME 多部分/相关的 SOAP 消息序列化,以独立于绑定的方式实现抽象 SOAP 传输优化功能。此实现依赖于 XML 二进制优化打包 (XOP) 格式。只能优化元素内容。
    • ...知道属性、非 base64 兼容的字符数据以及不在 base64Binary 数据类型的规范表示中的数据无法通过 XOP 成功优化”

    总而言之,MTOM 不是解决您问题的方法。

    其次

    HTTP 协议并非设计用于交换非常大的数据文件。正如您提到的 1TB (!) 数据,我建议采用完全不同的策略。

    原因是与更合适的协议相比,HTTP 协议有很多开销(尽管可以说如果从 A 到 Z 优化使用,即使用大 MTU 和块大小,开销比会显着降低)。但是请求-响应模型也不适合文件传输。如果没有有效的请求并行化和恢复方法,您还可能会遇到非常大的文件的严重传输问题。甚至不考虑防火墙、(反向)代理和其他可能认为这种流量特别异常或“越界”的工具。

    我的建议确实是找到使用方式 (S)FTP 进行大文件传输。该协议旨在。如果您的用例匹配,最终考虑点对点替代方案。

    但对于这个用例,绝对不要考虑 HTTP。除非您决定制作切片(因此需要多个请求),否则请使用压缩方法(最终堆叠)并优化整个传输链。

    祝你好运。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-21
      • 2012-06-16
      相关资源
      最近更新 更多