1

首先对不起我歪曲的英语:)

我在编写发送/接收大文件(~2Gb)的 Netty http 服务器时遇到了一些问题。我将非常感谢任何人的帮助或解释。

我的客户端应用程序(网络浏览器)通过 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);

服务器端是:

类 WebSocketServer:

             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));

类 HttpRequestServerHandler:

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:org.jboss 的 org.jboss.netty.buffer.BigEndianHeapChannelBuffer.(BigEndianHeapChannelBuffer.java:39) 的 org.jboss.netty.buffer.HeapChannelBuffer.(HeapChannelBuffer.java:47) 的 Java 堆空间。 netty.buffer.ChannelBuffers.buffer(ChannelBuffers.java:139) at org.jboss.netty.buffer.HeapChannelBufferFactory.getBuffer(HeapChannelBufferFactory.java:73) at org.jboss.netty.buffer.DynamicChannelBuffer.ensureWritableBytes(DynamicChannelBuffer.java: 84) 在 org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:457) 在 org.jboss.netty.buffer.AbstractChannelBuffer 的 org.jboss.netty.buffer.DynamicChannelBuffer.writeBytes(DynamicChannelBuffer.java:239) .writeBytes(AbstractChannelBuffer.java:450) 在 org.jboss.netty.handler.codec.http.HttpChunkAggregator。messageReceived(HttpChunkAggregator.java:140) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:302) at 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) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) at org.jboss.netty.channel.socket.nio.NioWorker.read (NioWorker.java:351)在 org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived (ReplayingDecoder.callDecode(ReplayingDecoder.java:506) java:443) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) at org.jboss.netty.channel .socket.nio.NioWorker.read(NioWorker.java:351)org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:506) 的展开AndFireMessageReceived(ReplayingDecoder.java:522) org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder. java:443) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) at org.jboss.netty.channel .socket.nio.NioWorker.read(NioWorker.java:351)fireMessageReceived(Channels.java:261) at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351)fireMessageReceived(Channels.java:261) at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351)

它甚至没有到达我的 messageReceived 处理程序。我可以假设一些内部 ChannelBuffer 溢出。我试图增加 HttpChunkAggregator(1024*1024*1024) 参数。但是,它没有帮助。我只看到一种解决方案 - 在客户端拆分文件(使用 html5),发送这些块,然后将它们粘贴到服务器上。但它似乎相当复杂。有没有更简单的方法来修复它(在 Netty 范围内)?

谢谢!最好的祝福。

4

3 回答 3

3

我认为你不应该使用HttpChunkAggregator.

这意味着您将不得不手动处理 HTTP 块。

有关详细信息,请参阅 Netty文件上传示例。

于 2011-12-27T21:14:20.250 回答
1

是的,一个更好的方法是将字节 [] 块“推送”到 fs,直到上传完成。因此,您无需将所有内容都保存在内存中。请注意,写入 fs 可能会“阻塞”,因此您应该考虑在其前面添加一个 ExecutionHandler。

于 2011-12-28T15:10:24.370 回答
0

它在一个叫做的东西中的事实说明HeapChannelBuffer了很多 - 你可能想要org.jboss.netty.buffer.DirectChannelBufferFactory在那里的某个地方,这样你的数据就不会存储在堆上。

于 2012-01-28T18:16:39.357 回答