zoukankan      html  css  js  c++  java
  • libcurl 下载上传

    近来一个新的项目需要使用到http。

    本来用socket来写一个的,后来发现功能实在太简单,有点捉襟见肘。

    于是改用libcur来做。

    首先下载libcur的源码,然后配置:

    1 ./configure --prefix=$HOME/csource/linux/ CFLAGS='-O2 -m32 -fPIC' --enable-optimize  --enable-static=libcurl.a --enable-ftp --without-zlib --disable-gopher --disable-rtsp --disable-dict --enable-proxy --disable-telnet  --enable-tftp   --disable-pop3   --disable-imap   --enable-smtp  --enable-ipv6  --enable-http -enable-crypto-auth  --without-gnutls --without-nss --without-ca-bundle --with-random=/dev/urandom

    然后编译

    1 make && make install

    代码如下,使用一个c++类来管理

    重点代码是DownloadFile和UploadFile

      1 #ifndef __MY_HTTP_CURL_H
      2 #define __MY_HTTP_CURL_H
      3 
      4 #include <string>
      5 
      6 typedef long long LongSize;
      7 
      8 typedef int (*pCallBack)(double dtotal, double dnow);
      9 
     10 class CMYHttpClient
     11 {
     12 public:
     13         CMYHttpClient();
     14         ~CMYHttpClient();
     15 
     16 public:
     17         /**
     18         * @brief 下载请求, 支持断点续传
     19         * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
     20         * @param strFile 输入参数,本地存储的文件名
     21         * @param timeout 输入参数,超时限制,0为永久等待
     22         * @return 返回是否下载成功:true成功,false失败
     23         */
     24         bool DownloadFile(const char *strUrl, const char *strFile, pCallBack cb = NULL, int timeout = 0);
     25         /**
     26         * @brief 获取将要下载的文件的大小,失败返回-1,成功返回非负
     27         * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
     28         * @return 返回文件的大小,失败返回-1
     29         */
     30         LongSize GetDownloadFileSize(const char *strUrl);
     31         /**
     32         * @brief 上载请求, 支持断点续传
     33         * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
     34         * @param strFile 输入参数,请求上载的文件名
     35         * @param timeout 输入参数,超时限制,0为永久等待
     36         * @return 返回是否下载成功:true成功,false失败
     37         */
     38         bool UploadFile(const char *strUrl, const char *strFile, pCallBack cb = NULL, int timeout = 0);
     39 
     40 public:
     41         /**
     42         * @brief HTTP POST请求
     43         * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
     44         * @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
     45         * @param strResponse 输出参数,返回的内容
     46         * @param nResponse 输入输出参数,输入缓冲区大小,返回读入缓冲区的内容大小
     47         * @param strFile 输入文件参数,返回的内容保存在这个文件中
     48         * @param strHeader 输入参数,需要额外指定的http头,如果输入为NULL,则忽略
     49         * @return 返回是否Post成功:0成功,非0失败
     50         */
     51         int Post(const char *strUrl, const char* strPost, size_t nPost,
     52                         const char *strFile, const char* strHeader);
     53         int Post(const char *strUrl, const char* strPost, size_t nPost,
     54                  char *strResponse, size_t &nResponse, const char *strHeader);
     55         int Post(const std::string &strUrl, const std::string &strPost,
     56                         const char *strFile, const char* strHeader);
     57         int Post(const std::string &strUrl, const std::string &strPost,
     58                 std::string &strResponse, const char *strHeader);
     59 
     60         /**
     61         * @brief HTTP GET请求
     62         * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
     63         * @param strFile 输入文件参数,返回的内容保存在这个文件中
     64         * @param strResponse 输出参数,返回的内容
     65         * @param nResponse 输入输出参数,输入缓冲区大小,返回读入缓冲区的内容大小
     66         * @return 返回是否Get成功:0成功,非0失败
     67         */
     68         int Get(const char *strUrl, const char *strFile);
     69         int Get(const char *strUrl, std::string &strResponse);
     70         int Get(const char *strUrl, char *strResponse, size_t &nResponse);
     71         int Get(const std::string &strUrl, char *strResponse, size_t &nResponse);
     72         int Get(const std::string &strUrl, std::string &strResponse);
     73 
     74         /**
     75         * @brief HTTPS POST请求,无证书版本
     76         * @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
     77         * @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
     78         * @param strResponse 输出参数,返回的内容
     79         * @param strHeader 输入参数,需要额外指定的http头,如果输入为NULL,则忽略
     80         * @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
     81         * @return 返回是否Post成功:0成功,非0失败
     82         */
     83         int Posts(const char *strUrl, const char *strPost, size_t nPost,
     84                         const char *strFile, const char *strHeader, const char *pCaPath);
     85         int Posts(const std::string &strUrl, const std::string &strPost,
     86                         const char *strFile, const char *strHeader, const char *pCaPath);
     87         int Posts(const char *strUrl, const char *strPost, size_t nPost,
     88                 char *strResponse, size_t &nResponse, const char *strHeader,
     89                 const char *pCaPath);
     90         int Posts(const std::string &strUrl, const std::string &strPost,
     91                         std::string &strResponse, const char *strHeader, const char *pCaPath);
     92 
     93         /**
     94         * @brief HTTPS GET请求,无证书版本
     95         * @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
     96         * @param strResponse 输出参数,返回的内容
     97         * @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
     98         * @return 返回是否Post成功
     99         */
    100         int Gets(const std::string &strUrl, std::string &strResponse,
    101                         const char *pCaPath = NULL);
    102 
    103 public:
    104         void SetDebug(bool bDebug);
    105         void AbortOperation(bool bAbort = true) { m_bAbort = bAbort; }
    106 
    107 private:
    108         bool m_bDebug;          //是否打开debug
    109         bool m_bAbort;          //是否放弃操作
    110 
    111         std::string m_strFile;  //需要下载的文件或者上传的文件
    112 
    113         pCallBack       m_fCB;  //上传或者下载时的进度回调函数
    114         LongSize        m_lUploadPos;   //上传文件的进度
    115 
    116         static int OnProgress(void *pClient, curl_off_t dltotal, curl_off_t dlnow,
    117                         curl_off_t ultotal, curl_off_t ulnow);
    118         static size_t OnWriteBuffer2File(char* buffer, size_t size, size_t nmemb, void* arg);
    119         static size_t OnReadFile2Buffer(char *buffer, size_t size, size_t nmemb, void* arg);
    120 };
    121 
    122 #endif

    几个主要方法,其中https的编译需要openssl,所以我没做支持。

      1 #include "curl/curl.h"
      2 #include <string>
      3 #include <fstream>
      4 #include <iostream>
      5 #include <sstream>
      6 
      7 #include "HttpClient.h"
      8 
      9 
     10 using namespace std;
     11 
     12 CMYHttpClient::CMYHttpClient() :
     13 #ifdef _DEBUG
     14         m_bDebug(true),
     15 #else
     16         m_bDebug(false),
     17 #endif
     18         m_bAbort(false),
     19         m_fCB(NULL),
     20         m_lUploadPos(0)
     21 {
     22 
     23 }
     24 
     25 CMYHttpClient::~CMYHttpClient()
     26 {
     27 
     28 }
     29 
     30 static int OnDebug(CURL *, curl_infotype itype, char *pData, size_t size, void *)
     31 {
     32         if(itype == CURLINFO_TEXT)
     33         {
     34                 //printf("[TEXT]%s
    ", pData);
     35         }
     36         else if(itype == CURLINFO_HEADER_IN)
     37         {
     38                 printf("[HEADER_IN]%s
    ", pData);
     39         }
     40         else if(itype == CURLINFO_HEADER_OUT)
     41         {
     42                 printf("[HEADER_OUT]%s
    ", pData);
     43         }
     44         else if(itype == CURLINFO_DATA_IN)
     45         {
     46                 printf("[DATA_IN]%s
    ", pData);
     47         }
     48         else if(itype == CURLINFO_DATA_OUT)
     49         {
     50                 printf("[DATA_OUT]%s
    ", pData);
     51         }
     52 
     53         return 0;
     54 }
     55 
     56 int CRGHttpClient::OnProgress(void *pClient, curl_off_t dltotal, curl_off_t dlnow,
     57                 curl_off_t ultotal, curl_off_t ulnow)
     58 {
     59         CMYHttpClient* pThis = (CMYHttpClient *)pClient;
     60         if(NULL == pThis || pThis->m_bAbort)
     61         {
     62                 //Returning a non-zero value from this callback will cause libcurl to abort
     63                 //the transfer and return CURLE_ABORTED_BY_CALLBACK.
     64                 return __LINE__;
     65         }
     66         else
     67         {
     68                 if(pThis->m_fCB)
     69                 {
     70                         pThis->m_fCB((double)dltotal, (double)dlnow);
     71                 }
     72 #ifdef _DEBUG
     73                 if(dltotal)
     74                 {
     75                         cout << "total bytes expects to download: " << dltotal
     76                                 << " and downloaded: " << dlnow << "
    ";
     77                 }
     78                 else if(ultotal)
     79                 {
     80                         cout << "total bytes expects to upload: " << ultotal
     81                                 << " and uploaded: " << ulnow << "
    ";
     82                 }
     83 #endif
     84 
     85                 return 0;
     86         }
     87 }
     88 
     89 size_t CMYHttpClient::OnWriteBuffer2File(char* buffer, size_t size, size_t nmemb, void* arg)
     90 {
     91         CMYHttpClient* pThis = (CMYHttpClient *)arg;
     92         if(NULL == pThis || pThis->m_bAbort ||
     93                         NULL == buffer)
     94         {
     95                 return 0;
     96         }
     97 
     98         const char* strFile = pThis->m_strFile.c_str();
     99 
    100         ofstream outfile(strFile, ofstream::binary | ofstream::app);
    101         if(outfile.good())
    102         {
    103                 const char* pData = (const char *)buffer;
    104                 outfile.write(pData, size * nmemb);
    105 
    106                 return nmemb;
    107         }
    108 
    109         return 0;
    110 }
    111 
    112 size_t CMYHttpClient::OnReadFile2Buffer(char *buffer, size_t size, size_t nmemb, void* arg)
    113 {
    114         CMYHttpClient* pThis = (CMYHttpClient *)arg;
    115         if(NULL == pThis || NULL == buffer)
    116         {
    117                 return 0;
    118         }
    119 
    120         ifstream infile(pThis->m_strFile.c_str(), ifstream::binary);
    121         if(infile.good())
    122         {
    123                 infile.seekg(pThis->m_lUploadPos, infile.beg);
    124                 if(infile.eof() == false)
    125                 {
    126                         infile.read(buffer, size * nmemb);
    127                         pThis->m_lUploadPos += infile.gcount();
    128                         return infile.gcount();
    129                 }
    130         }
    131 
    132         return 0;
    133 }
    134 
    135 LongSize CMYHttpClient::GetDownloadFileSize(const char* strUrl)
    136 {
    137         if(NULL == strUrl)
    138                 return -1;
    139 
    140         CURL* curl = curl_easy_init();
    141         if(NULL == curl)
    142                 return -1;
    143 
    144         curl_easy_setopt(curl, CURLOPT_URL, strUrl);
    145         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
    146         curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
    147         CURLcode res = curl_easy_perform(curl);
    148         if(res == CURLE_OK) {
    149                 double sz = 0;
    150                 res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &sz);
    151 
    152                 curl_easy_cleanup(curl);
    153 
    154                 return (LongSize)sz;
    155         }
    156         else
    157         {
    158                 cout << curl_easy_strerror(res) << endl;
    159         }
    160 
    161         curl_easy_cleanup(curl);
    162 
    163         return -1;
    164 }
    165 
    166 bool CMYHttpClient::DownloadFile(const char* strUrl, const char* strFile, pCallBack cb, int timeout)
    167 {
    168         if(NULL == strUrl || NULL == strFile)
    169         {
    170                 return false;
    171         }
    172 
    173         //初始化curl库句柄
    174         CURL* curl = curl_easy_init();
    175         if(NULL == curl)
    176         {
    177                 return false;
    178         }
    179 
    180         m_strFile = string(strFile) + ".dl";
    181         m_fCB = cb;
    182         //支持断点续传,先获取文件大小,如果文件存在并且非空,则断点续传
    183         ifstream infile(m_strFile.c_str(), ifstream::binary);
    184         if(infile.good())
    185         {
    186                 infile.seekg(0, infile.end);
    187                 int length = infile.tellg();
    188                 infile.seekg(0, infile.beg);
    189                 if(length > 0)
    190                 {
    191                         stringstream ss;
    192                         ss << length;
    193                         ss << "-";
    194                         LongSize ltotal = GetDownloadFileSize(strUrl);
    195                         if(ltotal > 0)
    196                                 ss << ltotal;
    197                         string srange;
    198                         ss >> srange;
    199                         curl_easy_setopt(curl, CURLOPT_RANGE, srange.c_str());
    200                 }
    201         }
    202         infile.close();
    203 
    204         CURLcode res;
    205         if(m_bDebug)
    206         {
    207                 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
    208                 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    209         }
    210 
    211         curl_easy_setopt(curl, CURLOPT_URL, strUrl);
    212         curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    213         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteBuffer2File);
    214         curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
    215 
    216         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
    217         curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, OnProgress);
    218         curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this);
    219 
    220         /**
    221         * 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。
    222         * 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。
    223         */
    224         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    225         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 4); //wait for 4 seconds to connect to server
    226         curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);       //0 means block always
    227 
    228         AbortOperation(false);  //reset abort flag
    229         res = curl_easy_perform(curl);
    230 
    231         curl_easy_cleanup(curl);
    232 
    233         if(res != CURLE_OK)
    234         {
    235                 cout << curl_easy_strerror(res);
    236         }
    237         else
    238         {
    239 #ifdef _WIN32
    240                 DeleteFile(strFile);
    241                 MoveFile(m_strFile.c_str(), strFile);
    242 #else
    243                 unlink(strFile);
    244                 rename(m_strFile.c_str(), strFile);
    245 #endif
    246         }
    247 
    248 
    249         m_strFile.clear();
    250         m_fCB = NULL;
    251 
    252         return res == CURLE_OK;
    253 }
    254 
    255 bool CMYHttpClient::UploadFile(const char *strUrl, const char *strFile, pCallBack cb, int timeout)
    256 {
    257         if(NULL == strUrl || NULL == strFile)
    258         {
    259                 return false;
    260         }
    261 
    262         //初始化curl库句柄
    263         CURL* curl = curl_easy_init();
    264         if(NULL == curl)
    265         {
    266                 return false;
    267         }
    268 
    269         CURLcode res;
    270         m_fCB = cb;
    271         m_strFile = strFile;
    272         m_lUploadPos = 0;
    273 
    274         curl_easy_setopt(curl, CURLOPT_URL, strUrl);
    275         curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    276 
    277         curl_easy_setopt(curl, CURLOPT_READFUNCTION, OnReadFile2Buffer);
    278         curl_easy_setopt(curl, CURLOPT_READDATA, this);
    279         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
    280 
    281         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
    282         curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, OnProgress);
    283         curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this);
    284 
    285         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    286         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 4); //wait for 4 seconds to connect to server
    287         curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);       //0 means block always
    288 
    289         AbortOperation(false);  //reset abort flag
    290         res = curl_easy_perform(curl);
    291 
    292         curl_easy_cleanup(curl);
    293 
    294         m_strFile.clear();
    295         m_fCB = NULL;
    296 
    297         if(res != CURLE_OK)
    298         {
    299                 cout << curl_easy_strerror(res);
    300         }
    301 
    302         return res == CURLE_OK;
    303 }
  • 相关阅读:
    CalcIntegerLength
    ReadIniTest_GetPrivateProfileString
    map test
    逻辑判断
    AppDomain.Unload_MarshalByRefObject
    网络编程
    pymysql
    MySQL多表查询
    MySQL单表查询
    python3 中引用 HTMLTestRunner.py 模块的注意事项
  • 原文地址:https://www.cnblogs.com/jojodru/p/3945601.html
Copyright © 2011-2022 走看看