zoukankan      html  css  js  c++  java
  • 12篇学通C#网络编程——第三篇 HTTP应用编程(下)

        第三篇来的好晚啊,上一篇说了如何向服务器推送信息,这一篇我们看看如何"快好准"的从服务器下拉信息。

        网络上有很多大资源文件,比如供人下载的zip包,电影(你懂的),那么我们如何快速的进行下载,大家第一反应肯定就是多线程下载,

    那么这些东西是如何做的呢?首先我们可以从“QQ的中转站里面拉一个rar下来“。

    然后用fiddler监视一下,我们会发现一个有趣的现象:

    第一:7.62*1024*1024≈7990914  千真万确是此文件

    第二:我明明是一个http链接,tmd的怎么变成n多个了?有意思。

    好,我们继续往下看,看看这些链接都做了些什么?

    最终,我们发现http协议中有一个Conent—Range字段,能够把我们的文件总大小进行切分,然后并行下载,最后再进行合并,大概我们知道

    了什么原理,那么,我们强大的C#类库提供了AddRange来获取Http中资源的指定范围。

    既然进行了切分,那么首先一定要知道文件的ContentLength是多少,如果对http协议比较熟悉的话,当发送一个头信息过去,服务器返回的

    头信息中会包含很多东西,此时我们就知道要下载资源的大概情况,这个就有点“兵马未动,粮草先行“的感觉。

     1             var request = (HttpWebRequest)HttpWebRequest.Create(url);
     2 
     3             request.Method = "Head";
     4 
     5             request.Timeout = 3000;
     6 
     7             var response = (HttpWebResponse)request.GetResponse();
     8 
     9             var code = response.StatusCode;
    10 
    11             if (code != HttpStatusCode.OK)
    12             {
    13                 Console.WriteLine("下载资源无效!");
    14                 return;
    15             }
    16 
    17             var total = response.ContentLength;

    这里有个决策,到底是以下载量来决定线程数,还是以线程数来决定下载量,由于我们的下载取决于当前的网速,所以在这种场合下更好的方案是

    采用后者,这几天在闪存里面两次看到苍老师,肃然起敬,所以决定在不用线程和线程的情况下,看看下载仓老师的速度如何。

    图片大小(217.27KB)

    View Code
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Net;
      6 using System.Threading;
      7 using System.Threading.Tasks;
      8 using System.IO;
      9 using System.Collections.Concurrent;
     10 using System.Diagnostics;
     11 using System.Drawing;
     12 
     13 
     14 namespace ConsoleApplication1
     15 {
     16     public class Program
     17     {
     18         public static CountdownEvent cde = new CountdownEvent(0);
     19 
     20         //每个线程下载的字节数,方便最后合并
     21         public static ConcurrentDictionary<long, byte[]> dic = new ConcurrentDictionary<long, byte[]>();
     22 
     23         //请求文件
     24         public static string url = "http://www.pncity.net/bbs/data/attachment/forum/201107/30/1901108yyd8gnrs2isadrr.jpg";
     25 
     26         static void Main(string[] args)
     27         {
     28             for (int i = 0; i < 1; i++)
     29             {
     30                 Console.WriteLine("\n****************************\n第{0}次比较\n****************************", (i + 1));
     31 
     32                 //不用线程
     33                 //RunSingle();
     34 
     35                 //使用多线程
     36                 RunMultiTask();
     37             }
     38 
     39             Console.Read();
     40         }
     41 
     42         static void RunMultiTask()
     43         {
     44             Stopwatch watch = Stopwatch.StartNew();
     45 
     46             //开5个线程
     47             int threadCount = 5;
     48 
     49             long start = 0;
     50 
     51             long end = 0;
     52 
     53             var total = GetSourceHead();
     54 
     55             if (total == 0)
     56                 return;
     57 
     58             var pageSize = (int)Math.Ceiling((Double)total / threadCount);
     59 
     60             cde.Reset(threadCount);
     61 
     62             Task[] tasks = new Task[threadCount];
     63 
     64             for (int i = 0; i < threadCount; i++)
     65             {
     66                 start = i * pageSize;
     67 
     68                 end = (i + 1) * pageSize - 1;
     69 
     70                 if (end > total)
     71                     end = total;
     72 
     73                 var obj = start + "|" + end;
     74 
     75                 tasks[i] = Task.Factory.StartNew(j => new DownFile().DownTaskMulti(obj), obj);
     76             }
     77 
     78             Task.WaitAll(tasks);
     79 
     80             var targetFile = "C://" + url.Substring(url.LastIndexOf('/') + 1);
     81 
     82             FileStream fs = new FileStream(targetFile, FileMode.Create);
     83 
     84             var result = dic.Keys.OrderBy(i => i).ToList();
     85 
     86             foreach (var item in result)
     87             {
     88                 fs.Write(dic[item], 0, dic[item].Length);
     89             }
     90 
     91             fs.Close();
     92 
     93             watch.Stop();
     94 
     95             Console.WriteLine("多线程:下载耗费时间:{0}", watch.Elapsed);
     96         }
     97 
     98         static void RunSingle()
     99         {
    100             Stopwatch watch = Stopwatch.StartNew();
    101 
    102             if (GetSourceHead() == 0)
    103                 return;
    104 
    105             var request = (HttpWebRequest)HttpWebRequest.Create(url);
    106 
    107             var response = (HttpWebResponse)request.GetResponse();
    108 
    109             var stream = response.GetResponseStream();
    110 
    111             var outStream = new MemoryStream();
    112 
    113             var bytes = new byte[10240];
    114 
    115             int count = 0;
    116 
    117             while ((count = stream.Read(bytes, 0, bytes.Length)) != 0)
    118             {
    119                 outStream.Write(bytes, 0, count);
    120             }
    121 
    122             var targetFile = "C://" + url.Substring(url.LastIndexOf('/') + 1);
    123 
    124             FileStream fs = new FileStream(targetFile, FileMode.Create);
    125 
    126             fs.Write(outStream.ToArray(), 0, (int)outStream.Length);
    127 
    128             outStream.Close();
    129 
    130             response.Close();
    131 
    132             fs.Close();
    133 
    134             watch.Stop();
    135 
    136             Console.WriteLine("不用线程:下载耗费时间:{0}", watch.Elapsed);
    137         }
    138 
    139         //获取头信息
    140         public static long GetSourceHead()
    141         {
    142             var request = (HttpWebRequest)HttpWebRequest.Create(url);
    143 
    144             request.Method = "Head";
    145             request.Timeout = 3000;
    146 
    147             var response = (HttpWebResponse)request.GetResponse();
    148 
    149             var code = response.StatusCode;
    150 
    151             if (code != HttpStatusCode.OK)
    152             {
    153                 Console.WriteLine("下载的资源无效!");
    154                 return 0;
    155             }
    156 
    157             var total = response.ContentLength;
    158 
    159             Console.WriteLine("当前资源大小为:" + total);
    160 
    161             response.Close();
    162 
    163             return total;
    164         }
    165     }
    166 
    167     public class DownFile
    168     {
    169         // 多线程下载
    170         public void DownTaskMulti(object obj)
    171         {
    172             var single = obj.ToString().Split('|');
    173 
    174             long start = Convert.ToInt64(single.FirstOrDefault());
    175 
    176             long end = Convert.ToInt64(single.LastOrDefault());
    177 
    178             var request = (HttpWebRequest)HttpWebRequest.Create(Program.url);
    179 
    180             request.AddRange(start, end);
    181 
    182             var response = (HttpWebResponse)request.GetResponse();
    183 
    184             var stream = response.GetResponseStream();
    185 
    186             var outStream = new MemoryStream();
    187 
    188             var bytes = new byte[10240];
    189 
    190             int count = 0;
    191 
    192             while ((count = stream.Read(bytes, 0, bytes.Length)) != 0)
    193             {
    194                 outStream.Write(bytes, 0, count);
    195             }
    196 
    197             outStream.Close();
    198 
    199             response.Close();
    200 
    201             Program.dic.TryAdd(start, outStream.ToArray());
    202 
    203             Program.cde.Signal();
    204         }
    205     }
    206 }

          在下面的图中可以看出,我们的资源被分成了n段,在217.27KB的情况下,多线程加速还不是很明显,我们可以试试更大的文件,这里我就

    在本地放一个133M的rar文件。

            //请求文件
            public static string url = "http://localhost:56933/1.rar";

    现在看一下效果是非常明显的。

  • 相关阅读:
    5.19 省选模拟赛 T1 小B的棋盘 双指针 性质
    5.15 省选模拟赛 容斥 生成函数 dp
    5.15 省选模拟赛 T1 点分治 FFT
    5.15 牛客挑战赛40 B 小V的序列 关于随机均摊分析 二进制
    luogu P4929 【模板】舞蹈链 DLX
    CF 878E Numbers on the blackboard 并查集 离线 贪心
    5.10 省选模拟赛 拍卖 博弈 dp
    5.12 省选模拟赛 T2 贪心 dp 搜索 差分
    5.10 省选模拟赛 tree 树形dp 逆元
    luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树
  • 原文地址:https://www.cnblogs.com/huangxincheng/p/2509715.html
Copyright © 2011-2022 走看看