扩展 WebClient

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_17813937/article/details/82227946

 测试代码:

using UnityEngine;
using System;

public class NewBehaviourScript1 : MonoBehaviour {

	void Start () {
        try
        {
            WebClientEx webClient = new WebClientEx(5);
            webClient.DownloadString("https://www.baidu.com/");
        }
        catch (Exception e)
        {
            Debug.Log(e);
        }
	}
}

扩展函数:

using System.Collections.Specialized;
using System.ComponentModel;
using System.Net;
using System;
using System.IO;


public class DownloadProgressChangedEventArgsEx 
{
    public long BytesReceived { get; private set; }
    public long TotalBytesToReceive { get; private set; }
    public float ProgressPercentage { get; private set; }
    public object UserState;
    public DownloadProgressChangedEventArgsEx(long received, long toReceive, float progressPercentage, object userState) 
    {
        BytesReceived = received;
        TotalBytesToReceive = toReceive;
        ProgressPercentage = progressPercentage;
        UserState = userState;
    }
}

public class WebClientEx : WebClient
{
    public string m_Url;
    public int m_TimeOut;

    
    private DownloadFileRangeState state;

    public delegate void DownloadProgressChangedEventHandlerEx(object sender,DownloadProgressChangedEventArgsEx e);
    public event DownloadProgressChangedEventHandlerEx DownloadProgressChangedEx;
    public delegate void AsyncCompletedEventHandlerEx(object sender, AsyncCompletedEventArgs e);
    public event AsyncCompletedEventHandlerEx DownloadFileCompletedEx;


    public WebClientEx(int timeout)
    {
        m_TimeOut = 1000 * timeout;
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request;
        if (address.Scheme == "https")
        {
            ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return true; };
            request = (HttpWebRequest)base.GetWebRequest(address);
            request.ProtocolVersion = HttpVersion.Version10;
        }
        else
        {
            request = (HttpWebRequest)base.GetWebRequest(address);
        }

        request.Timeout = m_TimeOut;
        request.ReadWriteTimeout = m_TimeOut;
        m_Url = address.OriginalString;
        request.AllowAutoRedirect = false;
        request.AllowWriteStreamBuffering = true;


        CookieContainer cookieContainer = new CookieContainer();
        NameValueCollection collection = new NameValueCollection();
        collection.Add("Accept-Language", "zh-cn,zh;q=0.5");
        collection.Add("Accept-Encoding", "gzip,deflate");
        collection.Add("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
        collection.Add("Keep-Alive", "115");
        request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13";
        request.Headers.Add(collection);
        request.CookieContainer = cookieContainer;

        request.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) =>
        {
            if (remoteEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                return new IPEndPoint(IPAddress.IPv6Any, 0);
            else
                return new IPEndPoint(IPAddress.Any, 0);
        };

        return request;
    }

    public new void CancelAsync()
    {
        base.CancelAsync();
        if (state!=null && state.m_isRangeDownload) state.m_isRangeDownload = false;
    }

    public void DownloadFileRangeAsync(string url, string path)
    {
        DownloadFileRangeAsync(url, path, null);
    }
    
    /// <summary>
    /// 异步断点续传
    /// </summary>
    /// <param name="url"></param>
    /// <param name="path"></param>
    /// <param name="userState"></param>
    public void DownloadFileRangeAsync(string url, string path, object userState)
    {
        if (state != null && state.m_isRangeDownload)
            return;

        Loom.RunAsync(()=> {
            state = new DownloadFileRangeState(path,userState);
            state.onCompleted =()=> DownloadFileCompletedEx;
            state.m_isRangeDownload = true;
            long startPos = CheckFile(state);
            if (startPos == -1) return;

            try
            {
                state.m_Request = (HttpWebRequest)GetWebRequest(new Uri(url));
                state.m_Request.ReadWriteTimeout = m_TimeOut;
                state.m_Request.Timeout = m_TimeOut;
                if (startPos > 0) state.m_Request.AddRange((int)startPos);
                state.m_Respone = state.m_Request.GetResponse();
                state.m_Stream = state.m_Respone.GetResponseStream();
                var totalBytesReceived = state.m_Respone.ContentLength + startPos;
                var bytesReceived = startPos;
                //如果下载完成
                if (totalBytesReceived != 0 && bytesReceived >= totalBytesReceived)
                {
                    state.Close();
                    try
                    {
                        if (File.Exists(state.m_Path)) File.Delete(state.m_Path);
                        File.Move(state.m_TempPath, state.m_Path);
                    }
                    catch (Exception e)
                    {
                        state.m_Exception = e;
                        state.Close();
                    }
                }
                else
                {
                    WriteFile(state, startPos);
                }
            }
            catch (Exception e)
            {
                state.m_Exception = e;
            }
            finally
            {
                state.Close();
            }
        });
    }

    /// <summary>
    /// 检查文件
    /// </summary>
    /// <param name="state"></param>
    /// <returns></returns>
    private long CheckFile(DownloadFileRangeState state)
    {
        long startPos = 0;
        if (File.Exists(state.m_TempPath))
        {
            state.m_FileStream = File.OpenWrite(state.m_TempPath);
            startPos = state.m_FileStream.Length;
            state.m_FileStream.Seek(startPos, SeekOrigin.Current);
        }
        else
        {
            try
            {
                string direName = Path.GetDirectoryName(state.m_TempPath);
                if (!Directory.Exists(direName)) Directory.CreateDirectory(direName);
                state.m_FileStream = new FileStream(state.m_TempPath, FileMode.Create);
            }
            catch (Exception e)
            {
                state.m_Exception = e;
                
                startPos = -1;
                state.Close();
            }
        }
        return startPos;
    }

    /// <summary>
    /// 写入文件
    /// </summary>
    /// <param name="state"></param>
    /// <param name="startPos"></param>
    private void WriteFile(DownloadFileRangeState state, long startPos)
    {
        var bytesReceived = startPos;
        byte[] bytes = new byte[1024];
        bool isDownloadCompleted = false;
        var totalBytesReceived = state.m_Respone.ContentLength + startPos;

        int readSize = state.m_Stream.Read(bytes, 0, 1024);

        while (readSize > 0 && state.m_isRangeDownload)
        {
            lock (state.m_FileStream)
            {
                Loom.QueueOnMainThread(() =>
                {
                    if (DownloadProgressChangedEx != null)
                        DownloadProgressChangedEx(this, new DownloadProgressChangedEventArgsEx(bytesReceived, totalBytesReceived, ((float)bytesReceived / totalBytesReceived), state.m_UserState));
                });

                state.m_FileStream.Write(bytes, 0, readSize);// 将下载到的数据写入临时文件
                bytesReceived += readSize;

                // 判断是否下载完成
                // 下载完成将temp文件,改成正式文件
                if (totalBytesReceived != 0 && bytesReceived >= totalBytesReceived)
                {
                    state.Close();

                    try
                    {
                        if (File.Exists(state.m_Path)) File.Delete(state.m_Path);
                        File.Move(state.m_TempPath, state.m_Path);
                        isDownloadCompleted = true;
                    }
                    catch (Exception e)
                    {
                        state.m_Exception = e;
                        state.Close();
                    }
                }

                readSize = state.m_Stream.Read(bytes, 0, 1024);
            }

        }

        if (!isDownloadCompleted)
        {
            state.m_Exception = new Exception("Request for early closure");
        }
    }

    private class DownloadFileRangeState
    {
        private readonly string tmpSuffix = ".temp";

        public Func<AsyncCompletedEventHandlerEx> onCompleted;
        public HttpWebRequest m_Request = null;
        public WebResponse m_Respone = null;
        public Stream m_Stream = null;
        public FileStream m_FileStream = null;
        public Exception m_Exception = null;
        public bool m_isRangeDownload;
        public string m_TempPath;
        public string m_Path;
        public object m_UserState;
        

        public DownloadFileRangeState(string path, object userState)
        {
            this.m_Path = path;
            this.m_UserState = userState;
            m_TempPath = path + tmpSuffix;
        }

        public void Close()
        {
            if (m_FileStream != null)
            {
                m_FileStream.Flush();
                m_FileStream.Close();
                m_FileStream = null;
            }
            if (m_Stream != null) m_Stream.Close();
            if (m_Respone != null) m_Respone.Close();
            if (m_Request != null) m_Request.Abort();

            Loom.QueueOnMainThread(() => {
                if (m_Exception != null) GameError.NetworkError(m_Exception.Message);
                if (onCompleted() != null)
                    onCompleted()(this, new AsyncCompletedEventArgs(m_Exception, true, m_UserState));
            });
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_17813937/article/details/82227946
今日推荐