简体   繁体   English

netty 中的 http 分块文件传输立即完成

[英]http chunked file transfer in netty finished immediately

I'm writing a http file server with downloading file in multiple thread with netty .我正在编写一个 http 文件服务器,使用netty在多线程中下载文件。 When using only HttpServerCodec() , everything works perfect but OOM: direct buffer memory error.仅使用HttpServerCodec() ,一切正常,但 OOM:直接缓冲内存错误。 Then I turn to the ChunkedWriteHandler() handler.然后我转向ChunkedWriteHandler()处理程序。

But the problem is, the browser(new Edge) either say 'can't download file' or download a file with zero size.但问题是,浏览器(新 Edge)要么说“无法下载文件”,要么下载大小为零的文件。 I have no idea about this and need help, please.我对此一无所知,需要帮助,请。

The log show that the transfer process complete immediately without any time cost.日志显示传输过程立即完成,没有任何时间成本。

[main] INFO Main - Pick up path C:/Temp
[main] INFO dd.oliver.htp.HtpServer - Server start at 2333
[nioEventLoopGroup-3-1] INFO dd.oliver.htp.RequestHandler - Request C:/Temp/d.test.oliverdd
[nioEventLoopGroup-3-1] INFO dd.oliver.htp.RequestHandler - [id: 0xe5ce2ec6, L:/0:0:0:0:0:0:0:1:2333 - R:/0:0:0:0:0:0:0:1:63040] Transfer complete.

here is my code, which is referring netty example .这是我的代码,它指的是netty 示例

This is ChannelInitializer:这是 ChannelInitializer:

class HtpChannelInitializer(val basePath: String) : ChannelInitializer<SocketChannel>() {
    override fun initChannel(ch: SocketChannel) {
        ch.pipeline().addLast("HttpCodec", HttpServerCodec())
        ch.pipeline().addLast("HttpAggregator", HttpObjectAggregator(65536))
        ch.pipeline().addLast("HttpChunked", ChunkedWriteHandler())
        ch.pipeline().addLast("RequestHandle", RequestHandler(basePath))
    }
}

This is RequestHandler:这是请求处理程序:

import io.netty.channel.*
import io.netty.handler.codec.http.*
import io.netty.handler.codec.http.HttpVersion.HTTP_1_0
import io.netty.handler.stream.ChunkedFile
import org.slf4j.LoggerFactory
import java.io.File
import java.io.RandomAccessFile


private val logger = LoggerFactory.getLogger(RequestHandler::class.java)

class RequestHandler_test(val basePath: String) : SimpleChannelInboundHandler<HttpRequest>() {
    ...

    override fun channelReadComplete(ctx: ChannelHandlerContext) {
        ctx.flush()
    }

    override fun channelRead0(ctx: ChannelHandlerContext, msg: HttpRequest) {
        val path = basePath + msg.uri() // msg.uri() example: / or /a/b or /a/b/c.txt
        logger.info("Request $path")
        val file = File(path)
        if (file.isFile) {
            val rfile = RandomAccessFile(file, "r")
            // Line
            val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
            // Headers
            response.headers().set("Accept-Ranges", "bytes")
            response.headers().set("Content-Disposition", "attachment; filename=\"${file.name}\"")
            response.headers().set("Content-Type", "application/octet-stream")
            response.headers().set("Content-Length", "${rfile.length()}")
            if (!(msg.headers().contains("Connection") && msg.headers().get("Connection") == "keep-alive")) {
                response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
            } else if (msg.protocolVersion() == HTTP_1_0) {
                response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            }
            // Content
//                    response.content().writeBytes(rfile.channel, 0L, rfile.length().toInt())
//                    ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE)
            ctx.write(response)
            val sendFileFuture = ctx.write(
                HttpChunkedInput(ChunkedFile(rfile, 0, rfile.length(), 8192)),
                ctx.newProgressivePromise()
            )
            sendFileFuture.addListener(object : ChannelProgressiveFutureListener {
                override fun operationProgressed(
                    future: ChannelProgressiveFuture,
                    progress: Long,
                    total: Long
                ) {
                    if (total < 0) { // total unknown
                        logger.info(future.channel().toString() + " Transfer progress: " + progress)
                    } else {
                        logger.info(
                            future.channel().toString() + " Transfer progress: " + progress + " / " + total
                        )
                    }
                }

                override fun operationComplete(future: ChannelProgressiveFuture) {
                    logger.info(future.channel().toString() + " Transfer complete.")
                }
            })
            if (!(msg.headers().contains("Connection") && msg.headers().get("Connection") == "close")) {
                sendFileFuture.addListener(ChannelFutureListener.CLOSE)
            }
        }
    }

...
}

Got it!知道了! This post has encountered the same question.这个帖子也遇到了同样的问题。 It's DefaultFullHttpResponse which makes it wrong and everything will be right when change to DefaultHttpResponse .它是DefaultFullHttpResponse这使它出错,当更改为DefaultHttpResponse时一切都会正确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM