随笔- 120  评论- 797  文章- 4 

[缓存]C# HTTP多线程断点续传下载,关于迅雷的HTTP请求中的range标头的疑问

来源:http://topic.csdn.net/t/20061214/22/5231907.html

楼主
clamlp(静水流深)2006-12-14 22:53:06 在 .NET技术 / ASP.NET 提问

最近公司做一个基于智能客户端的项目,让用户在下载主程序后通过验证再下载配置文件和一个库(50多M),由于工作需要和兴趣我就请缨做一个多线程断点续传下载的组件.  
              开始是每接收一次LOCK流   定位再写入磁盘.结果线程越多越慢,阻塞在写磁盘上了,数据还在系统的TCP缓冲区里,还容易超时,  
  看来得用一个后台线程写磁盘.分配一个大的内存块用来异步写磁盘  
  可又有个问题:缓存多大,怎么区分个各线程的数据,长度  
  再Seek到相应的位置写入  
  请教各位   有何妙策!  
  ~~~~~~~~~~~~~~~~~~~~~~~~~~  
  别外   发现迅雷的多线程HTTP请求很奇怪  
  比如10个线程,文件长度为10000字节,  
  我用的是每个线程平均分一段range  
  线程1   range:0-999  
  线程2   range:1000-1999  
  .  
  .  
  .  
  线程10:range:9000-9999  
  而迅雷的请求是这样的  
  线程1:range   :0-9999  
  线程2:range   :1000-9999  
  线程3:range   :2000-9999  
  .  
  .  
  .  
  .  
  线程10:range:9000-9999  
  是不是WEB服务器有缓存优化,最先到达的请求要返回的内容有缓存在内存中后面的请求直接从内存中发送给client  
  而迅雷的客户端每个线程只读取1000个字节?? 问题点数:100、回复次数:25Top

1 楼balenoww(名花虽有主,锄头更无情,只要锄头挥得好,哪有墙角挖不倒!)回复于 2006-12-15 00:12:34 得分 1

UP

2 楼zhaochong12(超级大笨鸟)回复于 2006-12-15 08:04:05 得分 1

http://www.cnblogs.com/chiname/articles/179490.html  
   
   
  LZ提供的经验太好了!   谢谢了!

3 楼cangwu_lee(橙子)回复于 2006-12-15 12:49:56 得分 8

http   协议规定可以这么传送,那么   httpServer   实现就是了。   至于是不是缓存,就要看   http   Server   怎么做的,是不是呢?  
   
  下载的文件的大小一开始是知道的,flashGet   就是开始的时候就分配磁盘空间,那么你只要对应地写到磁盘文件的对应位置好了。

4 楼Skyleo_liu(回归网络生活)回复于 2006-12-15 13:00:08 得分 0

flashGet似乎是写在内存先,再打在硬盘的吧?

5 楼akirya(坏[其实偶不是什么所谓的坏人])回复于 2006-12-15 13:23:33 得分 10

而迅雷的请求是这样的  
  线程1:range   :0-9999  
  线程2:range   :1000-9999  
  线程3:range   :2000-9999  
  .  
  这样的好处是   服务器第二个线程速度几乎为0的时候,第一个线程还能将第二个线程的部分下载到。  
  属于一个应用层次上的技巧吧

6 楼yhnxxx(哼哼猪!)回复于 2006-12-15 13:28:01 得分 0

而迅雷的请求是这样的  
  线程1:range   :0-9999  
  线程2:range   :1000-9999  
  线程3:range   :2000-9999  
   
  这就是迅雷占资源的根源?。。。请教。。。

7 楼cancerser(都是混饭吃,记得要结帖)回复于 2006-12-15 14:03:54 得分 20

开始是每接收一次LOCK流   定位再写入磁盘.结果线程越多越慢,阻塞在写磁盘上了,数据还在系统的TCP缓冲区里,还容易超时  
  //这个问题你可以把文件打碎了写,也就是10个线程写10个文件,然后把这10个合并成一个  
  //驴子好像就是这样  
  看来得用一个后台线程写磁盘.分配一个大的内存块用来异步写磁盘  
  可又有个问题:缓存多大,怎么区分个各线程的数据,长度  
  //这个相对麻烦先,不过问题也很简单,缓存自己定义,每个线程我一般用100K-2M(根据网速)  
  //过程特殊,要先建一个和要下载文件一边大的文件(内容用0填充),原因看下去就知道了  
  //比如4个线程,每个线程的缓存是1M,文件是40M.每个线程下到1M后,写入文件  
  //只需要开着临时文件的流   随时写入就可以了(以上这种方法不爱用,老得看着流的位置,麻烦)  
  至于讯雷的  
  //个人认为   通过HTTP下载,请求是从你要开始的位置到文件结束也是合理的,你要控制的只是要下多少,而不用担心到那结束

8 楼cancerser(都是混饭吃,记得要结帖)回复于 2006-12-15 14:22:59 得分 0

具体的原因就是,比如网站只允许单线程下载,而你要开5个线程.1个下载,另外4个不停的重试,你总不能只下1/5吧

9 楼fish_yht(百行孝为先,万业勤为径。)回复于 2006-12-16 14:47:13 得分 0

来学习的

10 楼CCjian(默契)回复于 2006-12-16 16:51:22 得分 0

学习

11 楼zlkingdom(风之悲伤)回复于 2006-12-17 15:25:50 得分 5

LZ的猜想基本正确,迅雷的下载基本也是逐线程覆盖的。其实断点下载是应该这样的,要不有可以因为一个range的原因导致文件下载不全,在初始分配的时候我想应该每个range都是平均分配字节的,然后随着下载的过程动态调整(这点还比较难,还没有实验成功过)...

12 楼clamlp(静水流深)回复于 2006-12-18 22:13:25 得分 0

重点是range的分配  
  迅雷和flashget为什么不平均分配,  
  都是  
  range:xxxxxxx-  
  这样服务器返回的不是多出来了吗?

13 楼kicck(撒旦之吻)回复于 2006-12-20 21:16:45 得分 5

基本所有的数据流都是先写在内存中.再写到磁盘上吧...没有一个是接收过来就向文件中写吧.  
   
  如果真是这样倒还麻烦多了

14 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-12-20 22:16:50 得分 30

客户端向服务器端请求从某个起点开始读数据,然后当读取的数据大于一页(例如4K),就中断连接,多于一页的字节丢弃掉,然后把数据保存到磁盘上。  
   
  服务器端根据客户端的起点开始下载数据,也是一页一页下载的,每下载一页都要判断是否客户端还在线,如果不在线,则停止输出。  
   
  在这个方案中,客户端的页面大小和服务器端的页面大小完全可以不一样,这具有很好的灵活性性。因此,服务器端不知道客户端的页面大小,只要客户端在线,就按照自己的页面大小一直属处下去,从请求点到文件结尾。

15 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-12-20 22:20:55 得分 0

而迅雷的请求是这样的  
  线程1:range   :0-9999  
  线程2:range   :1000-9999  
  线程3:range   :2000-9999  
   
  不要因此就认为线程之间重复下载完整数据,这也太小看客户端程序了。下载线程并不需求超过一页的数据,它发这个参数上去但是仅仅有耐心等待一页数据下载,是完全可以的。

16 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-12-20 22:23:42 得分 0

例如4K     -->     例如64K

17 楼clamlp(静水流深)回复于 2006-12-20 22:25:59 得分 0

楼上的,服务器是我公司的呀.这样服务器的带宽,流量不是大了吗?  
  并发量就小了

18 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-12-20 22:40:39 得分 0

多线程下载协议就是这样设计的,为的是可靠性。服务器带宽、流量大是什么意思?可以限制线程数据呀,例如每个IP只能最多5个线程。

19 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-12-20 22:45:23 得分 0

服务器不但要限制线程数(Response.End),而且要限制速度(使用sleep)。这也是很简单的asp.net程序,大概不到50行代码就能报所有功能写好。这样的服务器端程序可以被通用的多线程客户端使用。  
   
  当然你也可以自己规定自己的协议,完全没有必要遵循协议的head参数。

20 楼clamlp(静水流深)回复于 2006-12-20 22:45:57 得分 0

磁盘缓存已经解决了.  
  是可以   ,我可以在线程中统计下载到多少字节后关闭连接  
  他为什么不平均,这样下载速度有更快吗?

21 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-12-20 22:51:30 得分 0

对服务器来说,不用平均,控制线程数量是一样可以保证最高效率的。

22 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-12-20 22:58:14 得分 0

“平均”似乎太技术化了,服务器端不知道两个重复地址的请求是否应该拒绝,此时仍然需要控制总线程数量。看起来“平均”有点过分复杂化了。

23 楼clamlp(静水流深)回复于 2006-12-20 23:29:34 得分 0

支持http1.1的web服务器都支持,其实就是服务器用多个线程向客户端发数据.  
  while(Client.IsConnectd)  
  {  
        send   range中请求的数据  
  }  
  我平均的话如果服务器不支持多线程,另一个线程可以一直重试,直到前一个线程下载完断开,这样后一个线程就可以连上了.  
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
  为了防止竟争对手等不怀好意的人狂下载,URL是肯定会被人知道的.  
  占用服务器带宽.采用验证.用什么方案比较好  
  就是只能通过客户端软件下载.软件中包含了用户信息.怎么验证?  
  把用户信息加在post后进行验证.把用户信息sha1再发也不好可能被截获.......  
  大侠有什么方案,分不够再加   
 

24 楼hnsjack(痞子龍㊣)回复于 2006-12-21 13:31:00 得分 20

要分麳了.呵呵.以后清多多指教

25 楼nxjbill(阿龙)回复于 2006-12-30 16:27:01 得分 0

这位兄弟,您是用SOCKET套接字来做,可以可以说一下,向服务器请求某个文件的某个范围的数据的命令?

posted on 2009-07-24 01:50 xerwin 阅读(...) 评论(...) 编辑 收藏