1

まず第一に、私の曲がった英語で申し訳ありません:)

大きなファイル (~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);

サーバー側は次のとおりです。

クラス 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.netty.buffer.HeapChannelBuffer.(HeapChannelBuffer.java:47) の Java ヒープ スペース。 org.jboss.netty.buffer.HeapChannelBufferFactory.getBuffer(HeapChannelBufferFactory.java:73) の netty.buffer.ChannelBuffers.buffer(ChannelBuffers.java:139) 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 org.jboss.netty.handler.codec.http.HttpChunkAggregator の .writeBytes(AbstractChannelBuffer.java:450)。org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:302) で messageReceived(HttpChunkAggregator.java:140) 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 org.jboss.netty.channel.socket.nio.NioWorker.read の org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) の .netty.channel.Channels.fireMessageReceived(Channels.java:274) (NioWorker.java:351)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)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)org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351) の fireMessageReceived(Channels.java:261)org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351) の fireMessageReceived(Channels.java:261)

私のmessageReceivedハンドラーにさえ到達しません。内部 ChannelBuffer の一部がオーバーフローしていると推測できます。HttpChunkAggregator(1024*1024*1024) パラメータを増やしてみました。しかし、それは役に立ちませんでした。クライアント側で(html5を使用して)ファイルを分割し、これらのチャンクを送信して、サーバーに貼り付けるという1つの解決策しかありません。しかし、それは非常に複雑なようです。それを修正する簡単な方法はありますか (Netty スコープ内)?

ありがとうございました!よろしくお願いします。

4

3 に答える 3

3

は使用しないほうがよいと思いますHttpChunkAggregator

これは、HTTP チャンクを手動で処理する必要があることを意味します。

詳細については、Nettyファイルのアップロードの例を参照してください。

于 2011-12-27T21:14:20.250 に答える
1

ええ、最善の方法は、アップロードが完了するまでbyte[]チャンクをfsに「プッシュ」することです。したがって、すべてをメモリに保持する必要はありません。fsへの書き込みが「ブロック」される可能性があることに注意してください。そのため、その前にExecutionHandlerを追加することを検討する必要があります。

于 2011-12-28T15:10:24.370 に答える