我们有一个用例,我们必须通过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 Wild Fly,Java 8

最佳答案

首先,提到极限

<http-listener name="default" socket-binding="http" max-post-size="104857600"/>
表示服务器将接受的整个POST请求的最大大小。
无论是否使用MTOM,是否使用块,您都只在这里发送带有一个POST请求的文件。使用块不会改变这一点-具有文件数据的所有块都是同一POST请求的一部分。
因此,它可以按预期工作:100M +个文件因限制而过大。
那我很确定这个结论

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

10-01 06:36
查看更多