我们有一个用例,必须通过http将大型数据文件从环境a传输到环境B。我们想要实现的是,发送方以块的形式发送数据,接收方开始以块的方式将数据写入文件。因此,我们决定使用MTOM。
Web服务代码:
@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"/>
这意味着数据不会写入Chunks中的文件,而是保存在内存中,然后在传输完成后写入文件。
我们如何在Chunks中实现将数据写入文件?我们不希望后记忆增加。文件大小最多可以达到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以上的文件相应地太大了。
那么,我很确定这个结论
这意味着数据不会写入Chunks中的文件,而是保存在内存中,然后在传输完成后写入文件。
是完全错误的。在内存中保留潜在的大卷是不安全的,所以服务器通常不会这样做,而是将这些卷放入一些临时文件中。
一些解释
Sudeep:这意味着数据不会写入Chunks中的文件,而是保存在内存中,然后在传输完成后写入文件。
-->那绝对不是真的
以下限制:
<http-listener name="default" socket-binding="http" max-post-size="104857600"/>
指示单个(最终分块的)POST请求的最大正文大小不能超过104857600字节。这与HTTP内容长度标头和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 Infoset
- SOAP消息的优化MIME多部分/相关序列化,以独立于绑定的方式实现抽象SOAP传输优化功能。此实现依赖于XML二进制优化封装(XOP)格式。只能优化元素内容
- 。。。知道属性、非base64兼容字符数据和不在base64Binary数据类型的规范表示中的数据不能通过XOP"成功地优化
总之,MTOM并不能解决您的问题。
第二
HTTP协议不是为交换非常大的数据文件而设计的。正如你提到的1TB(!)的数据,我建议采取完全不同的策略。
原因是与更合适的协议相比,HTTP协议有很多开销(尽管可以说,如果从a到Z最佳使用,即具有大的MTU和块大小,开销比率将显著降低)。但是请求-响应模型也不能很好地适应文件传输。如果没有有效的请求并行化和恢复方法,您可能还会遇到非常大的文件的严重传输问题。甚至不考虑防火墙、(反向)代理和其他可能认为这种流量特别异常或"异常"的工具;界外";。
我的建议是找到使用(S)FTP进行大文件传输的方法。这个协议的目的是。如果你的用例匹配,最终考虑对等替代方案。
但是在这个用例中,绝对不要考虑HTTP。除非您决定进行切片(并因此进行多个请求),否则请使用压缩方法(最终堆叠)并优化整个传输链。
祝你好运。