实现支持恢复的下载管理器

时间:2009-04-04 16:08:17

标签: http file-io download

我打算用C ++编写一个支持恢复的小型下载管理器(每次下载多个连接)。

根据我目前收集的信息,当发送http请求时,我需要添加一个带有“Range”键和值“bytes = startoff-endoff”的头字段。然后服务器返回一个http响应,其中包含这些偏移之间的数据。

我的想法大致是将文件拆分为每个文件允许的连接数,并使用适当的“范围”发送每个拆分部分的http请求。因此,如果我有一个4mb文件和4个允许的连接,我将文件拆分为4并且有4个http请求,每个都有适当的“范围”字段。实现恢复功能将涉及记住已经下载了哪些偏移,而不是直接请求这些偏移。

  • 这是正确的方法吗?
  • 如果Web服务器不支持恢复怎么办? (我的猜测是它会忽略“范围”而只是发送整个文件)
  • 发送http请求时,是否应该在范围内指定整个分割大小?或者可能会要求较小的碎片,比如每个请求1024k?
  • 在阅读数据时,我应该立即将其写入文件还是进行某种缓冲?我想写小块可能是浪费。
  • 我应该使用内存映射文件吗?如果我没记错的话,建议经常阅读而不是写(我可能是错的)。记忆明智吗?如果我同时有几个下载怎么办?
  • 如果我没有使用内存映射文件,是否应该按照允许的连接打开文件?或者当需要写入文件时只需寻求? (如果我确实使用了内存映射文件,这将非常简单,因为我可以简单地使用几个指针)。

注意:我可能会使用Qt,但这是一个普遍的问题所以我把代码留了下来。

7 个答案:

答案 0 :(得分:7)

关于请求/响应:

对于Range-d请求,您可以获得三种不同的响应:

206 Partial Content - 恢复支持和可能;检查Content-Range标题的大小/响应范围
200 OK - 不支持字节范围(“恢复”),整个资源(“文件”)遵循
416 Requested Range Not Satisfiable - 不正确的范围(过去的EOF等)

内容 - 范围usu。看起来像这样:Content-Range: bytes 21010-47000/47022,即字节start-end / total。

查看HTTP spec了解详细信息,尤其是第14.5,14.16和14.35节

答案 1 :(得分:4)

我不是C ++方面的专家,但是,我曾经做过一个需要类似功能的.net应用程序(下载安排,恢复支持,优先下载)

我使用了微软位(后台智能传输服务)组件 - 它是用c开发的。 Windows更新也使用BITS。我选择了这个解决方案,因为我认为自己并不是一个能够自己编写这个级别的程序员的好东西; - )

虽然我不确定你是否可以获得BITS的代码 - 我认为你应该只看一下它的文档,这可能有助于你理解它们是如何实现的,架构,接口等。

这是 - http://msdn.microsoft.com/en-us/library/aa362708(VS.85).aspx

答案 2 :(得分:3)

除了跟踪标记段的开始和每个段长度的偏移量(除非你想在恢复时计算它,这将涉及对偏移列表进行排序并计算其中两个之间的距离),你将需要检查服务器发送的HTTP响应的Accept-Ranges标头,以确保它支持使用Range标头。指定范围的最佳方法是“Range:bytes = START_BYTE-END_BYTE”,您请求的范围包括START_BYTE和END_BYTE字节,因此包含(END_BYTE-START_BYTE)+1个字节。

请求微块是我建议反对的,因为您可能会被阻止HTTP泛洪的防火墙规则列入黑名单。一般来说,我建议你不要制作小于1MB的块,并且不要超过10块。 根据您计划下载的控件,如果您有套接字级控件,您可以考虑至少每32K写一次,或者异步写入数据。

我无法对MMF的想法发表评论,但是如果下载的文件很大,这不会是一个好主意,因为你会占用大量内存并最终导致系统交换,这是< em>不高效。

关于处理块,你可以创建几个文件 - 每个段一个,可选地预先分配填充文件的磁盘空间,其数量与块的大小一样多(预分配可能会在你写入期间保存一些时间)下载,但会使下载开始变慢,然后最后只是将所有的块顺序写入最终文件。

您应该注意的一件事是,有几台服务器有最大值。并发连接限制,并且您无法提前了解它,因此您应该准备好处理http错误/超时并更改块的大小或创建块的队列,以防您创建更多的块最大。连接。

答案 3 :(得分:3)

我无法回答你的所有问题,但这是我对其中两个问题的回答。

块大小

关于块大小,您应该考虑两件事:

  1. 它们越小,发送HTTP请求的开销就越大。
  2. 对于较大的块,如果一次下载失败,则可能会重新下载相同的数据两次。
  3. 我建议你使用较小的数据块。你必须做一些测试,看看哪种尺寸最适合你的目的。

    在内存与文件

    您应该将数据块写入内存缓冲区,然后将其写入磁盘时将其写入内存缓冲区。如果要下载大文件,如果用户用完RAM,对用户来说可能会很麻烦。如果我没记错,IIS会在内存中存储小于256kb的请求,那么任何更大的请求都会写入磁盘,您可能需要考虑采用相同的方法。

答案 4 :(得分:2)

不是原始问题的答案,但另一件值得一提的是,可恢复的下载程序还应检查资源上的最后修改日期,然后再尝试抓取可能已更改的下一部分内容。

答案 5 :(得分:0)

在我看来,您希望限制每个下载块的大小。如果连接在数据部分的末尾中止,则大块可能会强制您重复下载数据。特别是连接速度较慢的问题。

答案 6 :(得分:0)

暂停恢复支持请看这个简单的例子 Simple download manager in Qt with puase/ resume support