zoukankan      html  css  js  c++  java
  • [WorldWind学习]19.WebDownload

      1 using System;
      2 using System.Diagnostics;
      3 using System.Globalization;
      4 using System.Net;
      5 using System.IO;
      6 using System.IO.Compression;
      7 using System.Threading;
      8 using System.Xml;
      9 using Utility;
     10 using WorldWind;
     11 
     12 namespace WorldWind.Net
     13 {
     14     public delegate void DownloadProgressHandler(int bytesRead, int totalBytes);
     15     public delegate void DownloadCompleteHandler(WebDownload wd);
     16 
     17     public enum DownloadType
     18     {
     19         Unspecified,
     20         Wms
     21     }
     22     /// <summary>
     23     /// 网络下载对象,负责下载数据
     24     /// </summary>
     25     public class WebDownload : IDisposable
     26     {
     27         #region Static proxy properties
     28 
     29         static public bool Log404Errors = false;
     30         static public bool useWindowsDefaultProxy = true;
     31         static public string proxyUrl = "";
     32         static public bool useDynamicProxy;
     33         static public string proxyUserName = "";
     34         static public string proxyPassword = "";
     35 
     36         #endregion
     37         public static string UserAgent = String.Format(
     38             CultureInfo.InvariantCulture,
     39             "World Wind v{0} ({1}, {2})",
     40             System.Windows.Forms.Application.ProductVersion,
     41             Environment.OSVersion.ToString(),
     42             CultureInfo.CurrentCulture.Name);
     43 
     44         //下载连接字符串
     45         public string Url;
     46 
     47         /// <summary>
     48         /// Memory downloads fills this stream
     49         /// </summary>
     50         public Stream ContentStream;
     51 
     52         public string SavedFilePath;
     53         public bool IsComplete;
     54 
     55         /// <summary>
     56         /// Called when data is being received.  
     57         /// Note that totalBytes will be zero if the server does not respond with content-length.
     58         /// 开始接收数据时回调
     59         /// 总的字节数为0,如果服务没有返回目录长度
     60         /// </summary>
     61         public DownloadProgressHandler ProgressCallback;
     62 
     63         /// <summary>
     64         /// Called to update debug window.
     65         /// 更新debug窗体,回调函数
     66         /// </summary>
     67         public static DownloadCompleteHandler DebugCallback;
     68 
     69         /// <summary>
     70         /// Called when a download has ended with success or failure
     71         /// 当下载成功或者失败时回调
     72         /// </summary>
     73         public static DownloadCompleteHandler DownloadEnded;
     74 
     75         /// <summary>
     76         /// Called when download is completed.  Call Verify from event handler to throw any exception.
     77         /// 下载完成时回调,调用验证事件是否抛出异常。
     78         /// </summary>
     79         public DownloadCompleteHandler CompleteCallback;
     80 
     81         public DownloadType DownloadType = DownloadType.Unspecified;
     82         public string ContentType;
     83         public int BytesProcessed;
     84         public int ContentLength;
     85 
     86         // variables to allow placefinder to use gzipped requests
     87         //  *default to uncompressed requests to avoid breaking other things
     88         public bool Compressed = false;
     89         public string ContentEncoding;
     90 
     91         /// <summary>
     92         /// The download start time (or MinValue if not yet started)
     93         /// </summary>
     94         public DateTime DownloadStartTime = DateTime.MinValue;
     95 
     96         internal HttpWebRequest request;
     97         internal HttpWebResponse response;
     98 
     99         protected Exception downloadException;
    100 
    101         protected bool isMemoryDownload;
    102         /// <summary>
    103         /// used to signal thread abortion; if true, the download thread was aborted
    104         /// </summary>
    105         private bool stopFlag = false;
    106         //下载线程
    107         protected Thread dlThread;
    108 
    109         /// <summary>
    110         /// Initializes a new instance of the <see cref="WebDownload"/> class.
    111         /// 构造函数,初始化下载对象
    112         /// </summary>
    113         /// <param name="url">The URL to download from.</param>
    114         public WebDownload(string url)
    115         {
    116             this.Url = url;
    117         }
    118 
    119         /// <summary>
    120         /// Initializes a new instance of the <see cref="T:WorldWind.Net.WebDownload"/> class.
    121         /// </summary>
    122         public WebDownload()
    123         {
    124         }
    125 
    126         /// <summary>
    127         /// Whether the download is currently being processed (active).
    128         /// 当前下载是否仍在进行
    129         /// </summary>
    130         public bool IsDownloadInProgress
    131         {
    132             get
    133             {
    134                 return dlThread != null && dlThread.IsAlive;
    135             }
    136         }
    137 
    138         /// <summary>
    139         /// Contains the exception that occurred during download, or null if successful.
    140         /// </summary>
    141         public Exception Exception
    142         {
    143             get
    144             {
    145                 return downloadException;
    146             }
    147         }
    148 
    149         /// <summary>
    150         /// Asynchronous download of HTTP data to file. 
    151         /// 异步下载Http数据,通过开启新线程实现。
    152         /// </summary>
    153         public void BackgroundDownloadFile()
    154         {
    155             if (CompleteCallback == null)
    156                 throw new ArgumentException("No download complete callback specified.");
    157             //实例化下载线程
    158             dlThread = new Thread(new ThreadStart(Download));
    159             dlThread.Name = "WebDownload.dlThread";
    160             dlThread.IsBackground = true;
    161             dlThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
    162             //开启后台下载线程
    163             dlThread.Start();
    164         }
    165 
    166         /// <summary>
    167         /// Asynchronous download of HTTP data to file.
    168         /// 异步下载Http数据,绑定下载完成后的回调函数。
    169         /// </summary>
    170         public void BackgroundDownloadFile(DownloadCompleteHandler completeCallback)
    171         {
    172             CompleteCallback += completeCallback;
    173             BackgroundDownloadFile();
    174         }
    175 
    176         /// <summary>
    177         /// Download image of specified type. (handles server errors for wms type)
    178         /// </summary>
    179         public void BackgroundDownloadFile(DownloadType dlType)
    180         {
    181             DownloadType = dlType;
    182             BackgroundDownloadFile();
    183         }
    184 
    185         /// <summary>
    186         /// Asynchronous download of HTTP data to in-memory buffer.
    187         /// 异步下载Http数据到内存缓冲区
    188         /// </summary>
    189         public void BackgroundDownloadMemory()
    190         {
    191             if (CompleteCallback == null)
    192                 throw new ArgumentException("No download complete callback specified.");
    193 
    194             isMemoryDownload = true;
    195             dlThread = new Thread(new ThreadStart(Download));
    196             dlThread.Name = "WebDownload.dlThread(2)";
    197             dlThread.IsBackground = true;
    198             dlThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
    199             dlThread.Start();
    200         }
    201 
    202         /// <summary>
    203         /// Asynchronous download of HTTP data to in-memory buffer. 
    204         /// </summary>
    205         public void BackgroundDownloadMemory(DownloadCompleteHandler completeCallback)
    206         {
    207             CompleteCallback += completeCallback;
    208             BackgroundDownloadMemory();
    209         }
    210 
    211         /// <summary>
    212         /// Download image of specified type. (handles server errors for WMS type)
    213         /// </summary>
    214         /// <param name="dlType">Type of download.</param>
    215         public void BackgroundDownloadMemory(DownloadType dlType)
    216         {
    217             DownloadType = dlType;
    218             BackgroundDownloadMemory();
    219         }
    220 
    221         /// <summary>
    222         /// Synchronous download of HTTP data to in-memory buffer. 
    223         /// </summary>
    224         public void DownloadMemory()
    225         {
    226             isMemoryDownload = true;
    227             Download();
    228         }
    229 
    230         /// <summary>
    231         /// Download image of specified type. (handles server errors for WMS type)
    232         /// </summary>
    233         public void DownloadMemory(DownloadType dlType)
    234         {
    235             DownloadType = dlType;
    236             DownloadMemory();
    237         }
    238 
    239         /// <summary>
    240         /// HTTP downloads to memory.
    241         /// </summary>
    242         /// <param name="progressCallback">The progress callback.</param>
    243         public void DownloadMemory(DownloadProgressHandler progressCallback)
    244         {
    245             ProgressCallback += progressCallback;
    246             DownloadMemory();
    247         }
    248 
    249         /// <summary>
    250         /// Synchronous download of HTTP data to in-memory buffer. 
    251         /// </summary>
    252         public void DownloadFile(string destinationFile)
    253         {
    254             SavedFilePath = destinationFile;
    255 
    256             Download();
    257         }
    258 
    259         /// <summary>
    260         /// Download image of specified type to a file. (handles server errors for WMS type)
    261         /// </summary>
    262         public void DownloadFile(string destinationFile, DownloadType dlType)
    263         {
    264             DownloadType = dlType;
    265             DownloadFile(destinationFile);
    266         }
    267 
    268         /// <summary>
    269         /// Saves a http in-memory download to file.
    270         /// </summary>
    271         /// <param name="destinationFilePath">File to save the downloaded data to.</param>
    272         public void SaveMemoryDownloadToFile(string destinationFilePath)
    273         {
    274             if (ContentStream == null)
    275                 throw new InvalidOperationException("No data available.");
    276 
    277             // Cache the capabilities on file system
    278             ContentStream.Seek(0, SeekOrigin.Begin);
    279             using (Stream fileStream = File.Create(destinationFilePath))
    280             {
    281                 if (ContentStream is MemoryStream)
    282                 {
    283                     // Write the MemoryStream buffer directly (2GB limit)
    284                     MemoryStream ms = (MemoryStream)ContentStream;
    285                     fileStream.Write(ms.GetBuffer(), 0, (int)ms.Length);
    286                 }
    287                 else
    288                 {
    289                     // Block copy
    290                     byte[] buffer = new byte[4096];
    291                     while (true)
    292                     {
    293                         int numRead = ContentStream.Read(buffer, 0, buffer.Length);
    294                         if (numRead <= 0)
    295                             break;
    296                         fileStream.Write(buffer, 0, numRead);
    297                     }
    298                 }
    299             }
    300             ContentStream.Seek(0, SeekOrigin.Begin);
    301         }
    302 
    303         /// <summary>
    304         /// Aborts the current download. 
    305         /// 终止当前下载
    306         /// </summary>
    307         public void Cancel()
    308         {
    309             CompleteCallback = null;
    310             ProgressCallback = null;
    311             if (dlThread != null && dlThread != Thread.CurrentThread)
    312             {
    313                 if (dlThread.IsAlive)
    314                 {
    315                     Log.Write(Log.Levels.Verbose, "WebDownload.Cancel() : stopping download thread...");
    316                     stopFlag = true;
    317                     if (!dlThread.Join(500))
    318                     {
    319                         Log.Write(Log.Levels.Warning, "WebDownload.Cancel() : download thread refuses to die, forcing Abort()");
    320                         dlThread.Abort();
    321                     }
    322                 }
    323                 dlThread = null;
    324             }
    325         }
    326 
    327         /// <summary>
    328         /// Notify event subscribers of download progress.
    329         /// </summary>
    330         /// <param name="bytesRead">Number of bytes read.</param>
    331         /// <param name="totalBytes">Total number of bytes for request or 0 if unknown.</param>
    332         private void OnProgressCallback(int bytesRead, int totalBytes)
    333         {
    334             if (ProgressCallback != null)
    335             {
    336                 ProgressCallback(bytesRead, totalBytes);
    337             }
    338         }
    339 
    340         /// <summary>
    341         /// Called with detailed information about the download.
    342         /// </summary>
    343         /// <param name="wd">The WebDownload.</param>
    344         private static void OnDebugCallback(WebDownload wd)
    345         {
    346             if (DebugCallback != null)
    347             {
    348                 DebugCallback(wd);
    349             }
    350         }
    351 
    352         /// <summary>
    353         /// Called when downloading has ended.
    354         /// </summary>
    355         /// <param name="wd">The download.</param>
    356         private static void OnDownloadEnded(WebDownload wd)
    357         {
    358             if (DownloadEnded != null)
    359             {
    360                 DownloadEnded(wd);
    361             }
    362         }
    363 
    364         /// <summary>
    365         /// Synchronous HTTP download
    366         /// 线程异步调用的方法Download中,采用请求响应同步下载数据
    367         /// </summary>
    368         protected void Download()
    369         {
    370             Log.Write(Log.Levels.Debug, "Starting download thread...");
    371 
    372             Debug.Assert(Url.StartsWith("http://"));
    373             DownloadStartTime = DateTime.Now;
    374             try
    375             {
    376                 try
    377                 {
    378                     // If a registered progress-callback, inform it of our download progress so far.
    379                     OnProgressCallback(0, 1);
    380                     OnDebugCallback(this);
    381 
    382                     // check to see if thread was aborted (multiple such checks within the thread function)
    383                     if (stopFlag)
    384                     {
    385                         IsComplete = true;
    386                         return;
    387                     }
    388 
    389 
    390                     // create content stream from memory or file
    391                     if (isMemoryDownload && ContentStream == null)
    392                     {
    393                         ContentStream = new MemoryStream();
    394                     }
    395                     else
    396                     {
    397                         // Download to file
    398                         string targetDirectory = Path.GetDirectoryName(SavedFilePath);
    399                         if (targetDirectory.Length > 0)
    400                             Directory.CreateDirectory(targetDirectory);
    401                         ContentStream = new FileStream(SavedFilePath, FileMode.Create);
    402                     }
    403 
    404                     // Create the request object.
    405                     request = (HttpWebRequest)WebRequest.Create(Url);
    406                     request.UserAgent = UserAgent;
    407 
    408 
    409                     if (this.Compressed)
    410                     {
    411                         request.Headers.Add("Accept-Encoding", "gzip,deflate");
    412                     }
    413                     if (stopFlag)
    414                     {
    415                         IsComplete = true;
    416                         return;
    417                     }
    418                     request.Proxy = ProxyHelper.DetermineProxyForUrl(
    419                         Url,
    420                         useWindowsDefaultProxy,
    421                         useDynamicProxy,
    422                         proxyUrl,
    423                         proxyUserName,
    424                         proxyPassword);
    425 
    426                     // TODO: probably better done via BeginGetResponse() / EndGetResponse() because this may block for a while
    427                     // causing warnings in thread abortion.
    428                     using (response = request.GetResponse() as HttpWebResponse)
    429                     {
    430                         // only if server responds 200 OK
    431                         if (response.StatusCode == HttpStatusCode.OK)
    432                         {
    433                             ContentType = response.ContentType;
    434                             ContentEncoding = response.ContentEncoding;
    435 
    436                             // Find the data size from the headers.
    437                             string strContentLength = response.Headers["Content-Length"];
    438                             if (strContentLength != null)
    439                             {
    440                                 ContentLength = int.Parse(strContentLength, CultureInfo.InvariantCulture);
    441                             }
    442                             //缓存字节数组,大小1500byte
    443                             byte[] readBuffer = new byte[1500];
    444                             using (Stream responseStream = response.GetResponseStream())
    445                             {
    446                                 while (true)
    447                                 {
    448                                     if (stopFlag)
    449                                     {
    450                                         IsComplete = true;
    451                                         return;
    452                                     }
    453 
    454                                     //  Pass do.readBuffer to BeginRead.
    455                                     int bytesRead = responseStream.Read(readBuffer, 0, readBuffer.Length);
    456                                     if (bytesRead <= 0)
    457                                         break;
    458 
    459                                     //TODO: uncompress responseStream if necessary so that ContentStream is always uncompressed
    460                                     //  - at the moment, ContentStream is compressed if the requesting code sets
    461                                     //    download.Compressed == true, so ContentStream must be decompressed 
    462                                     //    by whatever code is requesting the gzipped download
    463                                     //  - this hack only works for requests made using the methods that download to memory,
    464                                     //    requests downloading to file will result in a gzipped file
    465                                     //  - requests that do not explicity set download.Compressed = true should be unaffected
    466 
    467                                     ContentStream.Write(readBuffer, 0, bytesRead);
    468 
    469                                     BytesProcessed += bytesRead;
    470 
    471                                     // If a registered progress-callback, inform it of our download progress so far.
    472                                     OnProgressCallback(BytesProcessed, ContentLength);
    473                                     OnDebugCallback(this);
    474                                 }
    475                             }
    476 
    477                         }
    478                     }
    479 
    480                     HandleErrors();
    481                 }
    482                 catch (ThreadAbortException)
    483                 {
    484                     // re-throw to avoid it being caught by the catch-all below
    485                     Log.Write(Log.Levels.Verbose, "Re-throwing ThreadAbortException.");
    486                     throw;
    487                 }
    488                 catch (System.Configuration.ConfigurationException)
    489                 {
    490                     // is thrown by WebRequest.Create if App.config is not in the correct format
    491                     // TODO: don't know what to do with it
    492                     throw;
    493                 }
    494                 catch (Exception caught)
    495                 {
    496                     try
    497                     {
    498                         // Remove broken file download
    499                         if (ContentStream != null)
    500                         {
    501                             ContentStream.Close();
    502                             ContentStream = null;
    503                         }
    504                         if (SavedFilePath != null && SavedFilePath.Length > 0)
    505                         {
    506                             File.Delete(SavedFilePath);
    507                         }
    508                     }
    509                     catch (Exception)
    510                     {
    511                     }
    512                     SaveException(caught);
    513                 }
    514 
    515                 if (stopFlag)
    516                 {
    517                     IsComplete = true;
    518                     return;
    519                 }
    520 
    521                 if (ContentLength == 0)
    522                 {
    523                     ContentLength = BytesProcessed;
    524                     // If a registered progress-callback, inform it of our completion
    525                     OnProgressCallback(BytesProcessed, ContentLength);
    526                 }
    527 
    528                 if (ContentStream is MemoryStream)
    529                 {
    530                     ContentStream.Seek(0, SeekOrigin.Begin);
    531                 }
    532                 else if (ContentStream != null)
    533                 {
    534                     ContentStream.Close();
    535                     ContentStream = null;
    536                 }
    537 
    538                 OnDebugCallback(this);
    539 
    540                 if (CompleteCallback == null)
    541                 {
    542                     Verify();
    543                 }
    544                 else
    545                 {
    546                     CompleteCallback(this);
    547                 }
    548             }
    549             catch (ThreadAbortException)
    550             {
    551                 Log.Write(Log.Levels.Verbose, "Download aborted.");
    552             }
    553             finally
    554             {
    555                 IsComplete = true;
    556             }
    557 
    558             OnDownloadEnded(this);
    559         }
    560 
    561         /// <summary>
    562         /// Handle server errors that don't get trapped by the web request itself.
    563         /// </summary>
    564         private void HandleErrors()
    565         {
    566             // HACK: Workaround for TerraServer failing to return 404 on not found
    567             if (ContentStream.Length == 15)
    568             {
    569                 // a true 404 error is a System.Net.WebException, so use the same text here
    570                 Exception ex = new FileNotFoundException("The remote server returned an error: (404) Not Found.", SavedFilePath);
    571                 SaveException(ex);
    572             }
    573 
    574             // TODO: WMS 1.1 content-type != xml
    575             // TODO: Move WMS logic to WmsDownload
    576             if (DownloadType == DownloadType.Wms && (
    577                 ContentType.StartsWith("text/xml") ||
    578                 ContentType.StartsWith("application/vnd.ogc.se")))
    579             {
    580                 // WMS request failure
    581                 SetMapServerError();
    582             }
    583         }
    584 
    585         /// <summary>
    586         /// If exceptions occurred they will be thrown by calling this function.
    587         /// </summary>
    588         public void Verify()
    589         {
    590             if (Exception != null)
    591                 throw Exception;
    592         }
    593 
    594         /// <summary>
    595         /// Log download error to log file
    596         /// </summary>
    597         /// <param name="exception"></param>
    598         private void SaveException(Exception exception)
    599         {
    600             // Save the exception 
    601             downloadException = exception;
    602 
    603             if (Exception is ThreadAbortException)
    604                 // Don't log canceled downloads
    605                 return;
    606 
    607             if (Log404Errors)
    608             {
    609                 Log.Write(Log.Levels.Error, "HTTP", "Error: " + Url);
    610                 Log.Write(Log.Levels.Error + 1, "HTTP", "     : " + exception.Message);
    611             }
    612         }
    613 
    614         /// <summary>
    615         /// Reads the xml response from the server and throws an error with the message.
    616         /// </summary>
    617         private void SetMapServerError()
    618         {
    619             try
    620             {
    621                 XmlDocument errorDoc = new XmlDocument();
    622                 ContentStream.Seek(0, SeekOrigin.Begin);
    623                 errorDoc.Load(ContentStream);
    624                 string msg = "";
    625                 foreach (XmlNode node in errorDoc.GetElementsByTagName("ServiceException"))
    626                     msg += node.InnerText.Trim() + Environment.NewLine;
    627                 SaveException(new WebException(msg.Trim()));
    628             }
    629             catch (XmlException)
    630             {
    631                 SaveException(new WebException("An error occurred while trying to download " + request.RequestUri.ToString() + "."));
    632             }
    633         }
    634 
    635         #region IDisposable Members
    636 
    637         /// <summary>
    638         /// Performs application-defined tasks associated with freeing, releasing, or
    639         /// resetting unmanaged resources.
    640         /// </summary>
    641         public void Dispose()
    642         {
    643             if (dlThread != null && dlThread != Thread.CurrentThread)
    644             {
    645                 if (dlThread.IsAlive)
    646                 {
    647                     Log.Write(Log.Levels.Verbose, "WebDownload.Dispose() : stopping download thread...");
    648                     stopFlag = true;
    649                     if (!dlThread.Join(500))
    650                     {
    651                         Log.Write(Log.Levels.Warning, "WebDownload.Dispose() : download thread refuses to die, forcing Abort()");
    652                         dlThread.Abort();
    653                     }
    654                 }
    655                 dlThread = null;
    656             }
    657 
    658             if (request != null)
    659             {
    660                 request.Abort();
    661                 request = null;
    662             }
    663 
    664             if (ContentStream != null)
    665             {
    666                 ContentStream.Close();
    667                 ContentStream = null;
    668             }
    669 
    670             if (DownloadStartTime != DateTime.MinValue)
    671                 OnDebugCallback(this);
    672 
    673             GC.SuppressFinalize(this);
    674         }
    675         #endregion
    676     }
    677 }
    View Code

    该类基于Http协议,应用层。

    Socket有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。传输层

      流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;

      数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

  • 相关阅读:
    archlinux 安装deepin桌面连接wifi不能输入密码
    LinuxMint/Ubuntu 关机重启等待 90 秒问题的解决办法
    WPS for Linux 字体配置(字体缺失解决办法)
    mysql 找回密码
    SQL的四种连接-左外连接、右外连接、内连接、全连接
    springmvc+shiro应用配置
    java手机验证码实现
    maven+ssm+cxf3配置例子
    破碎之花--普西拉之歌
    HTML5示例程序地址
  • 原文地址:https://www.cnblogs.com/yhlx125/p/3334568.html
Copyright © 2011-2022 走看看