您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    Go项目实战:一步步构建一个并发文件下载器
    时间:2021-08-06 21:01 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    Go项目实战:一步步构建一个并发文件下载器

    大家好,我是 polarisxu。

    明天为大家带来一个实战项目。建议你一定要入手实际。

    在往下看之前,你不妨思索下,用 Go 如何完成一个并发下载器。

    01 原理

    关于效劳器上的某个文件,我们要并发下载到本地,很容易想到,应该将文件分红多个部分,然后开多个 goroutine 并发地去下载,最后将这多个部分兼并成一个文件,完成并发下载的目的。

    如今的成绩是,效劳器上的一个文件,我们怎样做到分红多个呢?

    这需求 HTTP 协议相关知识了。

    HTTP 协议有一个照应头:Accept-Ranges,效劳器经过该头来标识本身支持部分央求(partial requests),也叫范围央求。假设效劳端支持部分央求,我们就可以完成并发下载。该头有两个能够的值:

    Accept-Ranges: bytes 

    Accept-Ranges: none 

    none:不支持任何部分央求单位,由于其同等于没有前往此头部,因此很少运用。不过一些阅读器,比如 IE9,会依据该头部去禁用或许移除下载管理器的暂停按钮。

    bytes:部分央求的单位是 bytes (字节)。

    所以,我们在并发下载之前,应该先发起一个 Head 央求,来确认效劳端能否支持部分央求。比如:

    resp, err := http.Head("https://studygolang.com/dl/golang/go1.16.5.src.tar.gz"

    if err != nil { 

      return err 

     

    if resp.StatusCode == http.StatusOK && resp.Header.Get("Accept-Ranges") == "bytes" { 

      // 支持部分央求 

    确认了效劳器支持部分央求,接上去就是如何停止部分央求。

    这就用到 HTTP 的一个央求头部:Range。(概略参考: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Range )

    Range 告知效劳器前往文件的哪一部分。在一个 Range 头部中,可以一次性央求多个部分,效劳器会以 multipart 文件的方式将其前往。假设效劳器前往的是范围照应,需求运用 206 Partial Content 形状码。假设所央求的范围不合法,那么效劳器会前往 416 Range Not Satisfiable 形状码,表示客户端错误。效劳器允许疏忽 Range 首部,从而前往整个文件,形状码用 200。

    详细语法:

    Range: <unit>=<range-start>- 

    Range: <unit>=<range-start>-<range-end> 

    Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end> 

    Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end> 

    <unit>

    范围所采用的单位,通常是字节(bytes)。

    <range-start>

    一个整数,表示在特定单位下,范围的起始值。

    <range-end>

    一个整数,表示在特定单位下,范围的完毕值。这个值是可选的,假设不存在,表示此范围不断延伸到文档完毕。

    例如:

    Range: bytes=200-10002000-657619000

    掌握了以上知识点,最后要做的就是将下载上去的各个部分兼并成一个文件。需求留意各个部分的顺序,比如依据顺序,按 1、2、3 等编号。

    02 入手完成一个

    知道了原理不代表你真的就会了,我们应该实践入手完成一个,加深了解。

    在本地某个目录下创立目录:downloader。

    $ mkdir downloader 

    $ cd downloader 

    $ go mod init github.com/polaris1119/downloader 

    命令行参数控制

    为了让工具更好用,我们应该支持命令行参数,而不是代码写死一个,比如要下载的 URL、并发数、输入的文件名等。关于命令行参数控制,除了运用标准库 flag,我比较喜欢 github.com/urfave/cli,最新版本 v2。

    创立一个文件 main.go,内容如下:

    package main 

     

    import ( 

        "log" 

        "os" 

        "runtime" 

     

        "github.com/urfave/cli/v2" 

     

    func main() { 

      // 默许并发数 

        concurrencyN := runtime.NumCPU() 

     

        app := &cli.App{ 

            Name:  "downloader"

            Usage: "File concurrency downloader"

            Flags: []cli.Flag{ 

                &cli.StringFlag{ 

                    Name:     "url"

                    Aliases:  []string{"u"}, 

                    Usage:    "`URL` to download"

                    Required: true

                }, 

                &cli.StringFlag{ 

                    Name:    "output"

                    Aliases: []string{"o"}, 

                    Usage:   "Output `filename`"

                }, 

                &cli.IntFlag{ 

                    Name:    "concurrency"

                    Aliases: []string{"n"}, 

                    Value:   concurrencyN, 

                    Usage:   "Concurrency `number`"

                }, 

            }, 

            Action: func(c *cli.Context) error { 

          return nil 

            }, 

        } 

     

        err := app.Run(os.Args) 

        if err != nil { 

            log.Fatal(err) 

        } 

    执行 go mod tidy,下载必要的包。然后执行:

    $ go run main.go -h 

    NAME: 

       downloader - File concurrency downloader 

     

    USAGE: 

       downloader [global options] command [command options] [arguments...] 

     

    COMMANDS: 

       help, h  Shows a list of commands or help for one command 

     

    GLOBAL OPTIONS: 

       --url URL, -u URL                URL to download 

       --output filename, -o filename   Output filename 

       --concurrency number, -n number  Concurrency number (default8

    (责任编辑:admin)