1. 程式人生 > 程式設計 >深入學習C#網路程式設計之HTTP應用程式設計(下)

深入學習C#網路程式設計之HTTP應用程式設計(下)

第三篇來的好晚啊,上一篇說了如何向伺服器推送資訊,這一篇我們看看如何"快好準"的從伺服器下拉資訊。

網路上有很多大資原始檔,比如供人下載的zip包,電影(你懂的),那麼我們如何快速的進行下載,大家第一反應肯定就是多執行緒下載,

那麼這些東西是如何做的呢?首先我們可以從“QQ的中轉站裡面拉一個rar下來“。

深入學習C#網路程式設計之HTTP應用程式設計(下)

然後用fiddler監視一下,我們會發現一個有趣的現象:

第一:7.62*1024*1024≈7990914 千真萬確是此檔案

第二:我明明是一個http連結,tmd的怎麼變成n多個了?有意思。

深入學習C#網路程式設計之HTTP應用程式設計(下)

好,我們繼續往下看,看看這些連結都做了些什麼?

深入學習C#網路程式設計之HTTP應用程式設計(下)深入學習C#網路程式設計之HTTP應用程式設計(下)

最終,我們發現http協議中有一個Conent—Range欄位,能夠把我們的檔案總大小進行切分,然後並行下載,最後再進行合併,大概我們知道了什麼原理,那麼,我們強大的C#類庫提供了AddRange來獲取Http中資源的指定範圍。

既然進行了切分,那麼首先一定要知道檔案的ContentLength是多少,如果對http協議比較熟悉的話,當傳送一個頭資訊過去,伺服器返回的頭資訊中會包含很多東西,此時我們就知道要下載資源的大概情況,這個就有點“兵馬未動,糧草先行“的感覺。

深入學習C#網路程式設計之HTTP應用程式設計(下)

var request = (HttpWebRequest)HttpWebRequest.Create(url);

      request.Method = "Head";

      request.Timeout = 3000;

      var response = (HttpWebResponse)request.GetResponse();

      var code = response.StatusCode;

      if (code != HttpStatusCode.OK)
      {
        Console.WriteLine("下載資源無效!");
        return;
      }

      var total = response.ContentLength;

這裡有個決策,到底是以下載量來決定執行緒數,還是以執行緒數來決定下載量,由於我們的下載取決於當前的網速,所以在這種場合下更好的方案是

採用後者,這幾天在快閃記憶體裡面兩次看到蒼老師,肅然起敬,所以決定在不用執行緒和執行緒的情況下,看看下載倉老師的速度如何。

View Code 
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Net;
  using System.Threading;
  using System.Threading.Tasks;
  using System.IO;
  using System.Collections.Concurrent;
 using System.Diagnostics;
 using System.Drawing;
 
 
 namespace ConsoleApplication1
 {
   public class Program
   {
     public static CountdownEvent cde = new CountdownEvent(0);
 
     //每個執行緒下載的位元組數,方便最後合併
     public static ConcurrentDictionary<long,byte[]> dic = new ConcurrentDictionary<long,byte[]>();
 
     //請求檔案
     public static string url = "https://www.jb51.net/";
 
     static void Main(string[] args)
     {
       for (int i = 0; i < 1; i++)
       {
         Console.WriteLine("\n****************************\n第{0}次比較\n****************************",(i + 1));
 
         //不用執行緒
         //RunSingle();
 
         //使用多執行緒
         RunMultiTask();
       }
 
       Console.Read();
     }
 
     static void RunMultiTask()
     {
       Stopwatch watch = Stopwatch.StartNew();
 
       //開5個執行緒
       int threadCount = 5;
 
       long start = 0;
 
       long end = 0;
 
       var total = GetSourceHead();
 
       if (total == 0)
         return;
 
       var pageSize = (int)Math.Ceiling((Double)total / threadCount);
 
       cde.Reset(threadCount);
 
       Task[] tasks = new Task[threadCount];
 
       for (int i = 0; i < threadCount; i++)
       {
         start = i * pageSize;
 
         end = (i + 1) * pageSize - 1;
 
         if (end > total)
           end = total;
 
         var obj = start + "|" + end;
 
         tasks[i] = Task.Factory.StartNew(j => new DownFile().DownTaskMulti(obj),obj);
       }
 
       Task.WaitAll(tasks);
 
       var targetFile = "C://" + url.Substring(url.LastIndexOf('/') + 1);
 
       FileStream fs = new FileStream(targetFile,FileMode.Create);
 
       var result = dic.Keys.OrderBy(i => i).ToList();
 
       foreach (var item in result)
       {
         fs.Write(dic[item],dic[item].Length);
       }
 
       fs.Close();
 
       watch.Stop();
 
       Console.WriteLine("多執行緒:下載耗費時間:{0}",watch.Elapsed);
     }
 
     static void RunSingle()
     {
       Stopwatch watch = Stopwatch.StartNew();
 
       if (GetSourceHead() == 0)
         return;
 
       var request = (HttpWebRequest)HttpWebRequest.Create(url);
 
       var response = (HttpWebResponse)request.GetResponse();
 
       var stream = response.GetResponseStream();
 
       var outStream = new MemoryStream();
 
       var bytes = new byte[10240];
 
       int count = 0;
 
       while ((count = stream.Read(bytes,bytes.Length)) != 0)
       {
         outStream.Write(bytes,count);
       }
 
       var targetFile = "C://" + url.Substring(url.LastIndexOf('/') + 1);
 
       FileStream fs = new FileStream(targetFile,FileMode.Create);
 
       fs.Write(outStream.ToArray(),(int)outStream.Length);
 
       outStream.Close();
 
       response.Close();
 
       fs.Close();
 
       watch.Stop();
 
       Console.WriteLine("不用執行緒:下載耗費時間:{0}",watch.Elapsed);
     }
 
     //獲取頭資訊
     public static long GetSourceHead()
     {
       var request = (HttpWebRequest)HttpWebRequest.Create(url);
 
       request.Method = "Head";
       request.Timeout = 3000;
 
       var response = (HttpWebResponse)request.GetResponse();
 
       var code = response.StatusCode;
 
       if (code != HttpStatusCode.OK)
       {
         Console.WriteLine("下載的資源無效!");
         return 0;
       }
 
       var total = response.ContentLength;
 
       Console.WriteLine("當前資源大小為:" + total);
 
       response.Close();
 
       return total;
     }
   }
 
   public class DownFile
   {
     // 多執行緒下載
     public void DownTaskMulti(object obj)
     {
       var single = obj.ToString().Split('|');
 
       long start = Convert.ToInt64(single.FirstOrDefault());
 
       long end = Convert.ToInt64(single.LastOrDefault());
 
       var request = (HttpWebRequest)HttpWebRequest.Create(Program.url);
 
       request.AddRange(start,end);
 
       var response = (HttpWebResponse)request.GetResponse();
 
       var stream = response.GetResponseStream();
 
       var outStream = new MemoryStream();
 
       var bytes = new byte[10240];
 
       int count = 0;
 
       while ((count = stream.Read(bytes,count);
       }
 
       outStream.Close();
 
       response.Close();
 
       Program.dic.TryAdd(start,outStream.ToArray());
 
       Program.cde.Signal();
     }
   }
 }

深入學習C#網路程式設計之HTTP應用程式設計(下)

深入學習C#網路程式設計之HTTP應用程式設計(下)

深入學習C#網路程式設計之HTTP應用程式設計(下)

深入學習C#網路程式設計之HTTP應用程式設計(下)

在下面的圖中可以看出,我們的資源被分成了n段,在217.27KB的情況下,多執行緒加速還不是很明顯,我們可以試試更大的檔案,這裡我就

在本地放一個133M的rar檔案。

    //請求檔案
    public static string url = http://localhost:56933/1.rar;

現在看一下效果是非常明顯的。

深入學習C#網路程式設計之HTTP應用程式設計(下)

以上就是深入學習C#網路程式設計之HTTP應用程式設計(下)的詳細內容,更多關於C#網路程式設計之HTTP應用程式設計的資料請關注我們其它相關文章!