• Http协议的断点续传下载器,使用观察者模式监视下载进度,使用xml保存下载进度。


    下载使用Http协议,为了做到断点续传,在点击暂停后,将已下载的大小等数据通过Json存入xml中,当继续传输的时候从xml文件中读取大小继续下载(好几个月前写的,真的想不起来了)

    bool CHttpDownLoader::DownLoadData(LPCTSTR downloadedUrl, LPCTSTR strSavePath, LPCTSTR configFile)
    {
        m_InternetSession = new CInternetSession(HTTPINFO, 1, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_DONT_CACHE);
        CString strServer;
        CString strObject;
        DWORD dw;
        INTERNET_PORT nPort;
        CString strFilePath;
        CFileStatus fileStatus;
        DWORD start;
        DWORD end;
        DWORD runtime;
        DWORD LocalFileSize;
    
        runtime = 10;
        start = timeGetTime();
    
        //读取本地文件大小
        if (CFile::GetStatus(strSavePath, fileStatus))
        {
             LocalFileSize = fileStatus.m_size;
        }
        //解析URL字符串并返回服务的类型及组件 
        AfxParseURL(downloadedUrl, dw, strServer, strObject, nPort);
        //判断是否是HTTP服务器
        if (dw != AFX_INET_SERVICE_HTTP && dw != AFX_INET_SERVICE_HTTPS)
        {
            m_ErrorInfo.m_dwError = 0;
            m_ErrorInfo.m_strErrorMsg = (CString)downloadedUrl + L"网址不是http类型服务器";
            ErrorNotifyObserver(&m_ErrorInfo);
            return FALSE;
        }
        try{
                m_HttpConnection = m_InternetSession->GetHttpConnection(strServer,
                    dw == AFX_INET_SERVICE_HTTP ? INTERNET_FLAG_KEEP_CONNECTION : (INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE),
                    nPort);
                //二进制存储HTTP下载文件,阻止从缓存中加载文件
                m_HttpFile = m_HttpConnection->OpenRequest(_T("GET"), strObject,
                    NULL, 1, NULL, NULL,
                    INTERNET_FLAG_RELOAD | INTERNET_FLAG_TRANSFER_BINARY |
                    (dw == AFX_INET_SERVICE_HTTP ? INTERNET_FLAG_KEEP_CONNECTION : (INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE)));
                //发送HTTP请求到指定的服务器。
                m_HttpFile->SendRequest(NULL, 0, NULL, 0);
    
                DWORD dwFileSize;
                CString strFileSize;
                CString strBegin;
                strBegin.Format(TEXT("%d"), 0);
                //获取文件大小
                m_HttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, dwFileSize);
                m_HttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, strFileSize);
                if (dwFileSize != 0)
                {
                    //对HTTP请求操作添加一个或多个请求头
                    m_HttpFile->AddRequestHeaders(_T("Range:") + strBegin + _T("-") + strFileSize + _T("
    "));
                }
    
                CFile downloadedFile;
                DWORD len;
                if (m_overALL == true)
                {
                    USES_CONVERSION;
                    remove(T2A(strSavePath));
                }
                //设置下载模式,不存在的话创建文件,存在的话不会清空这个文件
                downloadedFile.Open(strSavePath, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite);
    
                // 设定每个数据包大小,通过这个调整下载速度,但是如果包特别大的话速度还是特别慢  
    CHAR szBuf[800] = { 0 }; DWORD dwSize = sizeof(szBuf); DWORD fileLength = downloadedFile.GetLength(); downloadedFile.SeekToEnd(); DWORD AllLength = dwFileSize; m_HttpFile->Seek(fileLength, CFile::begin); ReadTransmisson(configFile); m_Transmisson.m_httpFileSize = dwFileSize; //判断文件是否已经下载完成 if (LocalFileSize == dwFileSize) { if (m_overALL == false) { m_ErrorInfo.m_dwError = 0; m_ErrorInfo.m_strErrorMsg = (CString)downloadedUrl + L"文件已经下载"; ErrorNotifyObserver(&m_ErrorInfo); downloadedFile.Close(); return false; } } if (m_Transmisson.m_downloadedFileSize == 0) { while ((len = m_HttpFile->Read(szBuf, dwSize)) > 0) { fileLength += len; downloadedFile.Write(szBuf, len); ZeroMemory(szBuf, sizeof(szBuf)); m_Transmisson.m_downloadSpeed = (fileLength * 100.0) / AllLength; m_Transmisson.m_downloadAddress = downloadedUrl; float fSpeed = 0; fSpeed = (float)fileLength; fSpeed /= (float)((float)runtime / (float)1000); m_Transmisson.m_downloadKB = fSpeed / (float)1024; RecordTransmisson(downloadedUrl, configFile, dwFileSize, fileLength, m_Transmisson.m_downloadSpeed, runtime); m_Transmisson.m_downloadedFileSize = fileLength; m_Transmisson.m_runTime = runtime; DownloadedNotifyObserver(&m_Transmisson); end = timeGetTime(); runtime = end - start; if (runtime == 0) { runtime = 10; } if (m_exit == false) { downloadedFile.Close(); clear(); break; } } } //文件已经存在,进行断点续传 else { if (m_Transmisson.m_downloadAddress!= downloadedUrl) { m_ErrorInfo.m_dwError = 0; m_ErrorInfo.m_strErrorMsg = (CString)strSavePath + L"文件下载地址错误"; ErrorNotifyObserver(&m_ErrorInfo); downloadedFile.Close(); return false; } runtime= m_Transmisson.m_runTime+10; DWORD downloadedSize =m_Transmisson.m_downloadedFileSize; while ((len = m_HttpFile->Read(szBuf, dwSize)) > 0) { double speed = m_Transmisson.m_downloadSpeed; downloadedSize += len; fileLength += len; downloadedFile.Write(szBuf, len); ZeroMemory(szBuf, sizeof(szBuf)); m_Transmisson.m_downloadSpeed = (fileLength * 100.0) / AllLength; m_Transmisson.m_downloadedFileSize=fileLength; float fSpeed = 0; fSpeed = (float)fileLength; fSpeed /= (float)((float)runtime / (float)1000); m_Transmisson.m_downloadKB = fSpeed / (float)1024;             //存储下载文件大小
                RecordTransmisson(downloadedUrl, configFile, dwFileSize, (
    int)fileLength, m_Transmisson.m_downloadSpeed, runtime); DownloadedNotifyObserver(&m_Transmisson); end = timeGetTime() + m_Transmisson.m_runTime; runtime = end - start; if (runtime == 0) { runtime = 10; } if (m_exit == false) { downloadedFile.Close(); clear(); break; } } } downloadedFile.Close(); } catch (CInternetException *e) { m_ErrorInfo.m_dwError = e->m_dwError; TCHAR szErrorMsg[255] = { 0 }; e->GetErrorMessage(szErrorMsg, 255); m_ErrorInfo.m_strErrorMsg = szErrorMsg ; ErrorNotifyObserver(&m_ErrorInfo); e->Delete(); return FALSE; } return TRUE; }

    文件存储

    void CHttpDownLoader::RecordTransmisson(LPCTSTR downloadedUrl, LPCTSTR configFile, DWORD downloadFileSize, DWORD readedLenght, double downloadedSpeed, DWORD runTime)
    {
        USES_CONVERSION;
        string downloadAddress W2A(downloadedUrl);
    
        ofstream in;
        in.open(configFile, ios::trunc);
        if (!in.is_open())
        {
            m_ErrorInfo.m_dwError = 0;
            m_ErrorInfo.m_strErrorMsg = (CString)downloadedUrl + L"文件无法打开";
            ErrorNotifyObserver(&m_ErrorInfo);
            //没有成功的执行一个程序
        }
        in.clear();
        Document document;
        Document::AllocatorType& allocator = document.GetAllocator();
        Value root(kObjectType);
      
        root.AddMember("DownloadedAddress", StringRef(downloadAddress.c_str()), allocator);
        root.AddMember("FileSize", (uint64_t)downloadFileSize, allocator);
        root.AddMember("DownLoadSize", (uint64_t)readedLenght, allocator);
        root.AddMember("DownLoadPercentage", downloadedSpeed, allocator);
        root.AddMember("RunTime", (uint64_t)runTime, allocator);
    
        StringBuffer buffer;
        Writer<StringBuffer> writer(buffer);
        root.Accept(writer);
        std::string result = buffer.GetString();
        in << result;
        in.close();
    }
    
    void CHttpDownLoader::ReadTransmisson(LPCTSTR configFile)
    {
        USES_CONVERSION;
        FILE *config = fopen(T2A(configFile), "a");
        //移动指针到文件末尾
        fseek(config, 0, SEEK_END);
        //判断文件是否为空
        if (ftell(config) == 0)
        {
            fclose(config);
            m_Transmisson.m_httpFileSize = 0;
            m_Transmisson.m_downloadedFileSize = 0;
            m_Transmisson.m_downloadSpeed = 0;
            m_Transmisson.m_runTime = 0;
            configFile = NULL;
            return ;
        }
        else
        {
            fclose(config);
            Document doc;
            ifstream ifs(T2A(configFile), ios_base::binary);
            string str;
            std::copy(std::istream_iterator<unsigned char>(ifs), std::istream_iterator<unsigned char>(), back_inserter(str));
            doc.Parse<0>(str.c_str());
            Value & dress = doc["DownloadedAddress"];
            Value & fileSize = doc["FileSize"];
            Value & DownLoadedSize = doc["DownLoadSize"];
            Value & downloadSpeed = doc["DownLoadPercentage"];
            Value & runTime = doc["RunTime"];
    
            m_Transmisson.m_downloadAddress = dress.GetString();
            m_Transmisson.m_httpFileSize = fileSize.GetInt();
            m_Transmisson.m_downloadedFileSize = DownLoadedSize.GetInt();
            m_Transmisson.m_downloadSpeed = downloadSpeed.GetDouble();
            m_Transmisson.m_runTime = runTime.GetFloat();
        }
        configFile = NULL;
        return ;
    }

    观察者模式

    HttpDownLoaded.h
    
    class IDownloadObserver
    {
    public:
        //更新下载信息
        virtual void UpdateDownloadInfo(CString m_downloadAddress, double  speed, DWORD m_httpfileSize, DWORD m_downloadedFileSize, int m_downloadKB, DWORD runTime) = 0;
        //更新错误信息
        virtual void UpdateErrorMsg(DWORD errorID, CString strErrorMsg) = 0;
    };
    
    
    class CHttpDownLoader
    {
    public:
        CHttpDownLoader();
        virtual ~CHttpDownLoader();
    public:
        struct Transmisson
        {
            //下载地址
            CString m_downloadAddress;
            //文件大小
            DWORD m_httpFileSize;
            //已下载大小
            DWORD m_downloadedFileSize;
            //下载百分比
            double m_downloadSpeed;
    
            int m_downloadKB;
    
            DWORD m_runTime;
    
        } m_Transmisson;
    
        struct ErrorInfo
        {
            DWORD m_dwError;
            CString m_strErrorMsg;
        }m_ErrorInfo;
        //建立观察者
        void SetObserver(IDownloadObserver * pObserver);
        //更新下载速度数据
        void DownloadedNotifyObserver(Transmisson *pTransmisson);
        //更新错误信息数据
        void ErrorNotifyObserver(ErrorInfo *m_ErrorInfo);
    }
    HttpDownLoadDlg.h
    
    
    class CHttpDownLoadDlg : public CDialogEx, public IDownloadObserver
    {
    // 构造
    public:
        CHttpDownLoadDlg(CWnd* pParent = NULL);    // 标准构造函数
    
    // 对话框数据
        enum { IDD = IDD_HTTPDOWNLOAD_DIALOG };
    
        protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    
    
    // 实现
    protected:
       void UpdateDownloadInfo(CString m_downloadAddress, double  speed, DWORD m_httpfileSize, DWORD m_downloadedFileSize, int downloadKB, DWORD runTime);
        void UpdateErrorMsg(DWORD errorID, CString strErrorMsg);
    };
    #include "HttpDownLoaded.h"

    void
    CHttpDownLoader::SetObserver(IDownloadObserver * pObserver) { m_downloadTransmissonVectors.push_back(pObserver); m_errorMsgVectors.push_back(pObserver); } void CHttpDownLoader::DownloadedNotifyObserver(Transmisson *pTransmisson) { MSG msg; for (auto it = m_downloadTransmissonVectors.begin(); it != m_downloadTransmissonVectors.end(); it++) { (*it)->UpdateDownloadInfo(pTransmisson->m_downloadAddress, pTransmisson->m_downloadSpeed, pTransmisson->m_httpFileSize, pTransmisson->m_downloadedFileSize, pTransmisson->m_downloadKB, pTransmisson->m_runTime); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { ExitProcess(0); } TranslateMessage(&msg); DispatchMessage(&msg); } } } void CHttpDownLoader::ErrorNotifyObserver(ErrorInfo *m_ErrorInfo) { for (auto it = m_errorMsgVectors.begin(); it != m_errorMsgVectors.end(); it++) { (*it)->UpdateErrorMsg(m_ErrorInfo->m_dwError, m_ErrorInfo->m_strErrorMsg); } }
    #include "HttpDownLoadDlg.h"
    
    void CHttpDownLoadDlg::UpdateDownloadInfo(CString m_downloadAddress, double  speed, DWORD m_httpfileSize, DWORD m_downloadedFileSize, int downloadKB, DWORD runTime)
    {
        m_progress.SetPos((int)speed);
        CString strPercent, KBsec;
        strPercent.Format(L"%d%%", (int)speed);
        KBsec.Format(L"%d KB/秒", downloadKB);
        SetDlgItemText(IDC_PERCENT_TEXT, strPercent);
        SetDlgItemText(IDC_SPEED, KBsec);
        if (m_downloadedFileSize == m_httpfileSize)
        {
            CFile    tempFile;
            tempFile.Remove(L"E:\recod.config");
            MessageBox(L"文件下载完成!", L"OK", MB_ICONINFORMATION);
            exit(EXIT_SUCCESS);
        }
       
    }
    
    void CHttpDownLoadDlg::UpdateErrorMsg(DWORD errorID, CString strErrorMsg)
    {
    
    }

    代码下载

  • 相关阅读:
    CSS3相关编码规范
    WEB开发中常见的漏洞
    Python常用端口扫描
    33、Django实战第33天:我的消息
    32、Django实战第32天:我的收藏
    31、Django实战第31天:我的课程
    30、Django实战第30天:修改邮箱和用户信息
    29、Django实战第29天:修改密码和头像
    28、Django实战第28天:个人信息展示
    27、Django实战第27天:全局搜索功能开发
  • 原文地址:https://www.cnblogs.com/ye-ming/p/7838466.html
Copyright © 2020-2023  润新知