首先抱歉我的歪英语:)
在编写发送/接收大文件(~2Gb)的Netty http服务器时遇到一些问题。我非常感谢任何人的帮助或解释。
我的客户端应用程序(Web浏览器)通过XMLHttpRequest发送文件,如下所示:
var sampleFile = document.getElementById("sampleFile").files[0]; //chosen file by <input type="file" .../>
var xhr = new XMLHttpRequest();
xhr.open("POST","http://127.0.0.1:8091/upload/some_file_name.txt", true);
xhr.send(sampleFile);
服务器端是:
ServerBootstrap bootstrapHttp = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
bootstrapHttp.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(1024*1024*1024));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("deflater", new HttpContentCompressor());
pipeline.addLast("handler", new HttpRequestServerHandler());
return pipeline;
}
});
bootstrapHttp.bind(new InetSocketAddress(port));
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Object msg = e.getMessage();
if (msg instanceof HttpRequest) {
HttpRequest req = (HttpRequest)msg;
if (req.getMethod() != POST) {
return;
}
if (decodedURI.startsWith(UPLOAD_FILE_PATH)) {
HttpRequest request = (HttpRequest) e.getMessage();
RandomAccessFile raf = new RandomAccessFile("foobar.tmp", "rw");
ChannelBuffer buf = request.getContent();
FileChannel fChannel = raf.getChannel();
Channel msgChannel= e.getChannel();
fChannel.write( buf.toByteBuffer() );
raf.close();
fChannel.close();
msgChannel.close();
}
}
当我发送中等大小的文件时,一切都很有效。问题在于大文件(> 300Mb)。经过一段时间处理异常后:
java.lang.OutOfMemoryError:Java堆空间 在org.jboss.netty.buffer.HeapChannelBuffer。(HeapChannelBuffer.java:47) 在org.jboss.netty.buffer.BigEndianHeapChannelBuffer。(BigEndianHeapChannelBuffer.java:39) 在org.jboss.netty.buffer.ChannelBuffers.buffer(ChannelBuffers.java:139) 在org.jboss.netty.buffer.HeapChannelBufferFactory.getBuffer(HeapChannelBufferFactory.java:73) 在org.jboss.netty.buffer.DynamicChannelBuffer.ensureWritableBytes(DynamicChannelBuffer.java:84) 在org.jboss.netty.buffer.DynamicChannelBuffer.writeBytes(DynamicChannelBuffer.java:239) 在org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:457) 在org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:450) 在org.jboss.netty.handler.codec.http.HttpChunkAggregator.messageReceived(HttpChunkAggregator.java:140) 在org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:302) 在org.jboss.netty.handler.codec.replay.ReplayingDecoder.unfoldAndFireMessageReceived(ReplayingDecoder.java:522) 在org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:506) 在org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:443) 在org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274) 在org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) 在org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351)
它甚至没有到达我的messageReceived处理程序。我可以假设一些内部ChannelBuffer溢出。我试图增加HttpChunkAggregator(1024 * 1024 * 1024)参数。但是,这没有用。 我只看到一个解决方案 - 在客户端分割文件(使用html5),发送这些块,然后将它们粘贴在服务器上。 但它似乎相当复杂。有没有更简单的方法来修复它(在Netty范围内)?
谢谢! 最好的问候。
答案 0 :(得分:3)
答案 1 :(得分:1)
是的,更好的方法是将字节[]块“推”到fs,直到上传完成。因此,您不需要将所有内容保存在内存中。请注意,写入fs可能会“阻止”,因此您应该考虑在其前面添加一个ExecutionHandler。
答案 2 :(得分:0)
事实上,它在一个名为HeapChannelBuffer
的东西中说了很多 - 你可能想在那里的某个地方org.jboss.netty.buffer.DirectChannelBufferFactory
,这样你的数据就不会存储在堆上。