首页 > 代码库 > libcurl 下载上传

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;          //是否打开debug109         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\n", pData); 35         } 36         else if(itype == CURLINFO_HEADER_IN) 37         { 38                 printf("[HEADER_IN]%s\n", pData); 39         } 40         else if(itype == CURLINFO_HEADER_OUT) 41         { 42                 printf("[HEADER_OUT]%s\n", pData); 43         } 44         else if(itype == CURLINFO_DATA_IN) 45         { 46                 printf("[DATA_IN]%s\n", pData); 47         } 48         else if(itype == CURLINFO_DATA_OUT) 49         { 50                 printf("[DATA_OUT]%s\n", 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 << "\n"; 77                 } 78                 else if(ultotal) 79                 { 80                         cout << "total bytes expects to upload: " << ultotal 81                                 << " and uploaded: " << ulnow << "\n"; 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 = http://www.mamicode.com/(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         else157         {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 server226         curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);       //0 means block always227 228         AbortOperation(false);  //reset abort flag229         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         else238         {239 #ifdef _WIN32240                 DeleteFile(strFile);241                 MoveFile(m_strFile.c_str(), strFile);242 #else243                 unlink(strFile);244                 rename(m_strFile.c_str(), strFile);245 #endif246         }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 server287         curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);       //0 means block always288 289         AbortOperation(false);  //reset abort flag290         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 }

 

libcurl 下载上传