zoukankan      html  css  js  c++  java
  • boost 实现http断点续传

    // testc.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <fstream>
    #include <boost/asio.hpp>
    #include <boost/asio/ip/tcp.hpp>
    #include <boost/algorithm/string.hpp>
    
    using boost::asio::ip::tcp;
    
    struct HttpResponse
    {
    public:
        explicit HttpResponse(){ clear();}
        std::string http_version;        // 版本
        unsigned int status_code;        // 状态码
        std::string status_message;    // 状态
        std::string header;                    // HTTP包头
        std::string body;           // HTTP返回的内容
        std::string content_type;
        std::string modify_time;
        unsigned int content_length;
        unsigned int total_length;
        unsigned int offset;
    
        void clear()
        {
            http_version.clear();
            status_code = -1;
            status_message.clear();
            header.clear();
            content_type.clear();
            modify_time.clear();
            content_length = 0;
            total_length = 0;
            offset = 0;
            body.clear();
        }
    };
    
    struct DownloadInfo
    {
        DownloadInfo()
        {
            id = 0;
            url.clear();
            filename.clear();
            md5.clear();
            writesize = 0;
            continued = false;
            lasterr = 0;
            trycount = 0;
        }
        int id;
        std::string url;
        std::string filename;
        std::string md5;
        int writesize;
        bool continued;
        int lasterr;
        int trycount;
    };
    
    int  GetTempFileRange( const std::string& fn );
    bool GetHttpFile(const std::string& szHost, const std::string& szParam);
    bool AnalyseHeader(HttpResponse& result, std::string& packetString, int nEndHeader);
    bool WriteFile( const std::string& fn, int rangeStart, std::string& packetString, DownloadInfo* d_diCurrent );
    
    std::ofstream f_ofsSave;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        std::string szHost ("192.168.1.102");
        std::string szParam("/DoDo/aishen.mp4");
    
        GetHttpFile(szHost, szParam);
    
        return 0;
    }
    
    // 获取文件
    bool GetHttpFile(const std::string& szHost, const std::string& szParam)
    {
        // 创建下载信息
        DownloadInfo* d_diCurrent = new DownloadInfo();
        d_diCurrent->filename = "DownLoadFile";
        d_diCurrent->continued = true;
    
        if(d_diCurrent->continued) {
            d_diCurrent->filename = d_diCurrent->filename+std::string(".td");
        }
    
        try
        {
            boost::asio::io_service io_serv;
    
            // Get a list of endpoints corresponding to the server name.
            std::string szService ("http");
            std::string szIp = szHost;
            int i = szHost.find(":") ;
            if (i != -1)
            {
                szService = szHost.substr(i+1);
                szIp = szHost.substr(0, i);
            }
            tcp::resolver::query query(szIp, szService);
    
            tcp::resolver m_resolver(io_serv);
            // 创建SOCKET
            tcp::socket s_socket(io_serv); 
    
            tcp::resolver::iterator endpoint_iterator = m_resolver.resolve(query), end_it;
    
            // Try each endpoint until we successfully establish a connection.
            tcp::resolver::iterator it = boost::asio::connect(s_socket, endpoint_iterator);
    
            if(it == end_it)
                return false;
    
            boost::asio::streambuf request;
            {
                // 封装请求HTTP GET
                std::ostream request_stream(&request);        
    
                request_stream << "GET " ;
                request_stream << szParam << " HTTP/1.1
    ";
                request_stream << "Host: " << szHost << "
    ";
    
                request_stream << "Accept: */*
    ";
                request_stream << "Pragma: no-cache
    ";
                request_stream << "Cache-Control: no-cache
    ";
                request_stream << "Connection: close
    ";
    
                // 1. 是否开启断点续传, 如是则读取临时文件长度
                int rangeStart = 0;
                if (d_diCurrent->continued) {
                    rangeStart = GetTempFileRange(d_diCurrent->filename);
                    if (rangeStart) {
                        request_stream << "Range: bytes=" << rangeStart << "- 
    ";    
                    }
                    request_stream << "
    ";
                }
    
                boost::asio::write(s_socket, request);
    
                boost::asio::streambuf response;
                std::ostringstream packetStream;
                try
                {
                    // Read until EOF, writing data to output as we go.
                    bool hasReadHeader = false;
    
                    boost::system::error_code error;
    
                    HttpResponse result;
                    result.body.clear();
    
                    while (boost::asio::read(s_socket, response,
                        boost::asio::transfer_at_least(1), error))
                    {
                        packetStream.str("");
                        packetStream << &response;
    
                        std::string packetString = packetStream.str(); 
    
                        // 2. 是否已分析文件头
                        if (!hasReadHeader)
                        {
                            hasReadHeader = true;
                            // 取出http header
                            size_t nEndHeader = packetString.find("
    
    ");
                            if(nEndHeader == std::string::npos)
                                continue;
    
                            if(!AnalyseHeader(result, packetString, nEndHeader)) {
                                return false;
                            }
                        }
    
                        // 3. 写入文件
                        WriteFile(d_diCurrent->filename, rangeStart, packetString, d_diCurrent);
                    }
    
                    // 4. 关闭文件
                    f_ofsSave.close();
    
                    // 5. 文件改名
                    std::string fn = "DownLoadFile.db";
                    rename(d_diCurrent->filename.c_str(), fn.c_str());
    
                    if (error != boost::asio::error::eof)
                        throw boost::system::system_error(error);
    
                }
                catch (std::exception& e)
                {
                    std::cout << "Exception: " << e.what() << "
    ";
                    return false;
                }
            } 
        }
        catch(std::exception& e) {
            std::cout << "Exception: " << e.what() << "
    ";
            return false;
        }
    
        return true;
    }
    
    // *****************************************************
    // 分析文件头
    // *****************************************************
    bool AnalyseHeader(HttpResponse& result, std::string& packetString, int nEndHeader)
    {
        result.header = packetString.substr(0, nEndHeader);
    
        // Check that response is OK.
        std::istringstream response_stream(result.header);
        response_stream >> result.http_version;
        response_stream >> result.status_code;
    
        std::string strLine;
        std::getline(response_stream, strLine);
        while (!strLine.empty())
        {
            if (strLine.find("Content-Type:") != std::string::npos)
            {
                result.content_type = strLine.substr(strlen("Content-Type:"));
                result.content_type.erase(0, result.content_type.find_first_not_of(" "));
            }
            if (strLine.find("Content-Length:") != std::string::npos)
            {
                result.content_length = atoi(strLine.substr(strlen("Content-Length:")).c_str());
                result.total_length = result.content_length;
            }
            if (strLine.find("Last-Modified:") != std::string::npos)
            {
                result.modify_time = strLine.substr(strlen("Last-Modified:"));
                result.modify_time.erase(0, result.modify_time.find_first_not_of(" "));
            }    
            if (strLine.find("Content-Range: bytes") != std::string::npos)
            {
                std::string tmp = strLine.substr(strlen("Content-Range: bytes"));
                result.offset = atoi(tmp.substr(0, tmp.find('-')).c_str());
                int ipos = tmp.find('/');
                int ivalue = 0;
                if (ipos != std::string::npos)
                {
                    ivalue = atoi(tmp.substr(ipos+1).c_str());
                }
                if (ivalue) 
                    result.total_length = ivalue;
            }
            strLine.clear();
            std::getline(response_stream, strLine);
        }
    
        if ( result.http_version.substr(0, 5) != "HTTP/")
        {
            std::cout << "Invalid response
    ";
            return false;
        }
        if (result.status_code != 200 && result.status_code != 206)
        {
            std::cout << "Response returned with status code " 
                << result.status_code << "
    ";
            return false;
        }
    
        packetString.erase(0, nEndHeader + 4);
    
        return true;
    }
    
    // ************************************************************** 
    // 获取临时文件大小
    // ************************************************************** 
    int GetTempFileRange( const std::string& fn )
    {
        int rangeStart = 0;
        std::ifstream ifs;
        ifs.open(fn, std::ios_base::in | std::ios_base::binary );
        if (ifs.is_open()) {
            ifs.seekg(0, std::ios::end);
            rangeStart = ifs.tellg();
        }
        ifs.close();
    
        return rangeStart;
    }
    
    // **************************************************************
    // 写入文件
    // **************************************************************
    bool WriteFile( const std::string& fn, int rangeStart, std::string& packetString, DownloadInfo* d_diCurrent )
    {
        if (!f_ofsSave.is_open())
        {
            if (d_diCurrent->continued) 
            {
                f_ofsSave.open(fn, std::ios_base::out | std::ios_base::binary | std::ios_base::app );
                if (f_ofsSave.is_open()) 
                {
                    f_ofsSave.seekp(rangeStart);
                    d_diCurrent->writesize += rangeStart;
                    //int range = f_ofsSave.tellp();
                }
            }
            else
            {
                f_ofsSave.open(fn, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc );
            }
    
            if (!f_ofsSave.is_open()) 
            {
                return false;
            }
    
            d_diCurrent->writesize = 0;
        }
    
        try {
            f_ofsSave.write(packetString.c_str(), packetString.length());
            d_diCurrent->writesize += packetString.length();
        }
        catch (std::exception &e)
        {
            return false;
        }
    
        std::cout << " write size = "<<d_diCurrent->writesize<<"
    ";
    
        return true;
    }
  • 相关阅读:
    mapxtreme2005 改变选中的图元样式
    hdu 3044 Dog and dog
    jdoj 1008 最短路径问题 代码及分析
    jdoj 1402 特殊的数 代码及分析
    poj 1125 Stockbroker Grapevine 代码及分析
    hdu 1063 Exponentiation代码及分析
    堆和栈的区别 (转贴)
    文本长度控制
    一点设计上的创意,有机会就去实现
    IECookiesView (Cookies查看工具)绿色汉化版 V1.74
  • 原文地址:https://www.cnblogs.com/liaocheng/p/4284866.html
Copyright © 2011-2022 走看看