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

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

于是改用libcur来做。

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

 ./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

然后编译

 make && make install

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

重点代码是DownloadFile和UploadFile

 #ifndef __MY_HTTP_CURL_H
#define __MY_HTTP_CURL_H #include <string> typedef long long LongSize; typedef int (*pCallBack)(double dtotal, double dnow); class CMYHttpClient
{
public:
CMYHttpClient();
~CMYHttpClient(); public:
/**
* @brief 下载请求, 支持断点续传
* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
* @param strFile 输入参数,本地存储的文件名
* @param timeout 输入参数,超时限制,0为永久等待
* @return 返回是否下载成功:true成功,false失败
*/
bool DownloadFile(const char *strUrl, const char *strFile, pCallBack cb = NULL, int timeout = );
/**
* @brief 获取将要下载的文件的大小,失败返回-1,成功返回非负
* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
* @return 返回文件的大小,失败返回-1
*/
LongSize GetDownloadFileSize(const char *strUrl);
/**
* @brief 上载请求, 支持断点续传
* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
* @param strFile 输入参数,请求上载的文件名
* @param timeout 输入参数,超时限制,0为永久等待
* @return 返回是否下载成功:true成功,false失败
*/
bool UploadFile(const char *strUrl, const char *strFile, pCallBack cb = NULL, int timeout = ); public:
/**
* @brief HTTP POST请求
* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
* @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
* @param strResponse 输出参数,返回的内容
* @param nResponse 输入输出参数,输入缓冲区大小,返回读入缓冲区的内容大小
* @param strFile 输入文件参数,返回的内容保存在这个文件中
* @param strHeader 输入参数,需要额外指定的http头,如果输入为NULL,则忽略
* @return 返回是否Post成功:0成功,非0失败
*/
int Post(const char *strUrl, const char* strPost, size_t nPost,
const char *strFile, const char* strHeader);
int Post(const char *strUrl, const char* strPost, size_t nPost,
char *strResponse, size_t &nResponse, const char *strHeader);
int Post(const std::string &strUrl, const std::string &strPost,
const char *strFile, const char* strHeader);
int Post(const std::string &strUrl, const std::string &strPost,
std::string &strResponse, const char *strHeader); /**
* @brief HTTP GET请求
* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
* @param strFile 输入文件参数,返回的内容保存在这个文件中
* @param strResponse 输出参数,返回的内容
* @param nResponse 输入输出参数,输入缓冲区大小,返回读入缓冲区的内容大小
* @return 返回是否Get成功:0成功,非0失败
*/
int Get(const char *strUrl, const char *strFile);
int Get(const char *strUrl, std::string &strResponse);
int Get(const char *strUrl, char *strResponse, size_t &nResponse);
int Get(const std::string &strUrl, char *strResponse, size_t &nResponse);
int Get(const std::string &strUrl, std::string &strResponse); /**
* @brief HTTPS POST请求,无证书版本
* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
* @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
* @param strResponse 输出参数,返回的内容
* @param strHeader 输入参数,需要额外指定的http头,如果输入为NULL,则忽略
* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
* @return 返回是否Post成功:0成功,非0失败
*/
int Posts(const char *strUrl, const char *strPost, size_t nPost,
const char *strFile, const char *strHeader, const char *pCaPath);
int Posts(const std::string &strUrl, const std::string &strPost,
const char *strFile, const char *strHeader, const char *pCaPath);
int Posts(const char *strUrl, const char *strPost, size_t nPost,
char *strResponse, size_t &nResponse, const char *strHeader,
const char *pCaPath);
int Posts(const std::string &strUrl, const std::string &strPost,
std::string &strResponse, const char *strHeader, const char *pCaPath); /**
* @brief HTTPS GET请求,无证书版本
* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
* @param strResponse 输出参数,返回的内容
* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
* @return 返回是否Post成功
*/
int Gets(const std::string &strUrl, std::string &strResponse,
const char *pCaPath = NULL); public:
void SetDebug(bool bDebug);
void AbortOperation(bool bAbort = true) { m_bAbort = bAbort; } private:
bool m_bDebug; //是否打开debug
bool m_bAbort; //是否放弃操作 std::string m_strFile; //需要下载的文件或者上传的文件 pCallBack m_fCB; //上传或者下载时的进度回调函数
LongSize m_lUploadPos; //上传文件的进度 static int OnProgress(void *pClient, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow);
static size_t OnWriteBuffer2File(char* buffer, size_t size, size_t nmemb, void* arg);
static size_t OnReadFile2Buffer(char *buffer, size_t size, size_t nmemb, void* arg);
}; #endif

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

 #include "curl/curl.h"
#include <string>
#include <fstream>
#include <iostream>
#include <sstream> #include "HttpClient.h" using namespace std; CMYHttpClient::CMYHttpClient() :
#ifdef _DEBUG
m_bDebug(true),
#else
m_bDebug(false),
#endif
m_bAbort(false),
m_fCB(NULL),
m_lUploadPos()
{ } CMYHttpClient::~CMYHttpClient()
{ } static int OnDebug(CURL *, curl_infotype itype, char *pData, size_t size, void *)
{
if(itype == CURLINFO_TEXT)
{
//printf("[TEXT]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_IN)
{
printf("[HEADER_IN]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_OUT)
{
printf("[HEADER_OUT]%s\n", pData);
}
else if(itype == CURLINFO_DATA_IN)
{
printf("[DATA_IN]%s\n", pData);
}
else if(itype == CURLINFO_DATA_OUT)
{
printf("[DATA_OUT]%s\n", pData);
} return ;
} int CRGHttpClient::OnProgress(void *pClient, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
{
CMYHttpClient* pThis = (CMYHttpClient *)pClient;
if(NULL == pThis || pThis->m_bAbort)
{
//Returning a non-zero value from this callback will cause libcurl to abort
//the transfer and return CURLE_ABORTED_BY_CALLBACK.
return __LINE__;
}
else
{
if(pThis->m_fCB)
{
pThis->m_fCB((double)dltotal, (double)dlnow);
}
#ifdef _DEBUG
if(dltotal)
{
cout << "total bytes expects to download: " << dltotal
<< " and downloaded: " << dlnow << "\n";
}
else if(ultotal)
{
cout << "total bytes expects to upload: " << ultotal
<< " and uploaded: " << ulnow << "\n";
}
#endif return ;
}
} size_t CMYHttpClient::OnWriteBuffer2File(char* buffer, size_t size, size_t nmemb, void* arg)
{
CMYHttpClient* pThis = (CMYHttpClient *)arg;
if(NULL == pThis || pThis->m_bAbort ||
NULL == buffer)
{
return ;
} const char* strFile = pThis->m_strFile.c_str(); ofstream outfile(strFile, ofstream::binary | ofstream::app);
if(outfile.good())
{
const char* pData = (const char *)buffer;
outfile.write(pData, size * nmemb); return nmemb;
} return ;
} size_t CMYHttpClient::OnReadFile2Buffer(char *buffer, size_t size, size_t nmemb, void* arg)
{
CMYHttpClient* pThis = (CMYHttpClient *)arg;
if(NULL == pThis || NULL == buffer)
{
return ;
} ifstream infile(pThis->m_strFile.c_str(), ifstream::binary);
if(infile.good())
{
infile.seekg(pThis->m_lUploadPos, infile.beg);
if(infile.eof() == false)
{
infile.read(buffer, size * nmemb);
pThis->m_lUploadPos += infile.gcount();
return infile.gcount();
}
} return ;
} LongSize CMYHttpClient::GetDownloadFileSize(const char* strUrl)
{
if(NULL == strUrl)
return -; CURL* curl = curl_easy_init();
if(NULL == curl)
return -; curl_easy_setopt(curl, CURLOPT_URL, strUrl);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, );
curl_easy_setopt(curl, CURLOPT_NOBODY, );
CURLcode res = curl_easy_perform(curl);
if(res == CURLE_OK) {
double sz = ;
res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &sz); curl_easy_cleanup(curl); return (LongSize)sz;
}
else
{
cout << curl_easy_strerror(res) << endl;
} curl_easy_cleanup(curl); return -;
} bool CMYHttpClient::DownloadFile(const char* strUrl, const char* strFile, pCallBack cb, int timeout)
{
if(NULL == strUrl || NULL == strFile)
{
return false;
} //初始化curl库句柄
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return false;
} m_strFile = string(strFile) + ".dl";
m_fCB = cb;
//支持断点续传,先获取文件大小,如果文件存在并且非空,则断点续传
ifstream infile(m_strFile.c_str(), ifstream::binary);
if(infile.good())
{
infile.seekg(, infile.end);
int length = infile.tellg();
infile.seekg(, infile.beg);
if(length > )
{
stringstream ss;
ss << length;
ss << "-";
LongSize ltotal = GetDownloadFileSize(strUrl);
if(ltotal > )
ss << ltotal;
string srange;
ss >> srange;
curl_easy_setopt(curl, CURLOPT_RANGE, srange.c_str());
}
}
infile.close(); CURLcode res;
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, );
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
} curl_easy_setopt(curl, CURLOPT_URL, strUrl);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteBuffer2File);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, );
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, OnProgress);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this); /**
* 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。
* 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。
*/
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, );
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ); //wait for 4 seconds to connect to server
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); //0 means block always AbortOperation(false); //reset abort flag
res = curl_easy_perform(curl); curl_easy_cleanup(curl); if(res != CURLE_OK)
{
cout << curl_easy_strerror(res);
}
else
{
#ifdef _WIN32
DeleteFile(strFile);
MoveFile(m_strFile.c_str(), strFile);
#else
unlink(strFile);
rename(m_strFile.c_str(), strFile);
#endif
} m_strFile.clear();
m_fCB = NULL; return res == CURLE_OK;
} bool CMYHttpClient::UploadFile(const char *strUrl, const char *strFile, pCallBack cb, int timeout)
{
if(NULL == strUrl || NULL == strFile)
{
return false;
} //初始化curl库句柄
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return false;
} CURLcode res;
m_fCB = cb;
m_strFile = strFile;
m_lUploadPos = ; curl_easy_setopt(curl, CURLOPT_URL, strUrl);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_READFUNCTION, OnReadFile2Buffer);
curl_easy_setopt(curl, CURLOPT_READDATA, this);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, );
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, OnProgress);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, );
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ); //wait for 4 seconds to connect to server
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); //0 means block always AbortOperation(false); //reset abort flag
res = curl_easy_perform(curl); curl_easy_cleanup(curl); m_strFile.clear();
m_fCB = NULL; if(res != CURLE_OK)
{
cout << curl_easy_strerror(res);
} return res == CURLE_OK;
}

libcurl 下载上传的更多相关文章

  1. WP8.1 Study17:网络之后台下载/上传及HttpClient

    一.后台下载/上传 1.简介 使用BackgroundTransferGroup可以十分方便操作上传及下载文件,BackgroundDownloader和BackgroundUploader类中的方法 ...

  2. https 协议下服务器根据网络地址下载上传文件问题

    https 协议下服务器根据网络地址下载上传文件遇到(PKIX:unable to find valid certification path to requested target 的问题) 使用h ...

  3. git下载/上传文件提示:git did not exit cleanly

    问题:git操作下载/上传文件,提示信息如下 TortoiseGit-git did not exit cleanly (exit code 1) TortoiseGit-git did not ex ...

  4. 亚马逊S3下载上传文件

    引用网址: http://www.jxtobo.com/27697.html 下载 CloudBerry Explorer http://www.cloudberrylab.com/download- ...

  5. C#FTP操作类含下载上传删除获取目录文件及子目录列表等等

    ftp登陆格式  : ftp://[帐号]:[密码]@[IP]:[端口] ftp://用户名:密码@FTP服务器IP或域名:FTP命令端口/路径/文件名 直接上代码吧,根据需要选择函数,可根据业务自己 ...

  6. C语言 HTTP上传文件-利用libcurl库上传文件

    原文  http://justwinit.cn/post/7626/ 通常情况下,一般很少使用C语言来直接上传文件,但是遇到使用C语言编程实现文件上传时,该怎么做呢? 借助开源的libcurl库,我们 ...

  7. 一行代码实现Okhttp,Retrofit,Glide下载上传进度监听

    https://mp.weixin.qq.com/s/bopDUFMB7EiK-MhLc3KDXQ essyan 鸿洋 2017-06-29 本文作者 本文由jessyan投稿. jessyan的博客 ...

  8. vc libcurl 模拟上传文件

    http://www.cnblogs.com/killbit/p/5393301.html 附上这篇文章,因为当时就已经想到了模拟上传,但是因为时间关系,所以就直接用PHP写了.现在改进一下,用VC+ ...

  9. Ubuntu 16.04通过Trickle限制某个软件的下载/上传速度

    在Linux下没有Windows使用360那样去限制某个软件的速度. 但是通过Trickle可以设置某个软件的网速,但是前提是通过Trickle命令连带启动这个软件才可以,不能中途去设置. 比如现在很 ...

随机推荐

  1. js dom操作获取节点的一些方法

    在复习javascript基础的时候,整理了一下js中获取节点的一些常用的方法,见代码: //js获取下一个兄弟节点 function getNextSibling(eleObj){ var next ...

  2. Linux crontab相关

    定时自动启动任务crontab命令 文章目录 [隐藏] crontab简介 crontab用法 crontab例子 每个操作系统都有它的自动定时启动程序的功能,Windows有它的任务计划,而Linu ...

  3. js复选框全选

    <input name='chkAll' type='checkbox' id='chkAll' onclick='CheckAll(this.form)' value='checkbox'&g ...

  4. Excel导入mysql数据库

    步骤一:选取要导入的数据快儿,另外要多出一列,如下图:    步骤二:  将选中的数据快儿拷贝到一个新建的表格工作薄,然后“另存为” ->“文本文件(制表符分割)(*.txt)”,假如存到“D: ...

  5. android market 选择

    通过Java包名直接定位到你的App http://market.android.com/details?id=<java包名>或者market://details?id=<java ...

  6. android图片缓存框架Android-Universal-Image-Loader

    http://blog.csdn.net/king_is_everyone/article/details/34107081 最近跟同学们做了一个创业项目,其实跟以前做项目不同,以前大多数都是做web ...

  7. sbt 配置

    1. SBT使用local maven repository,下载的库依然放在 ~/.m2/repository 2. SBT assembly 会把依赖库打包到一个jar包,需要使用assembly ...

  8. Java中如何分析一个案列---猫狗案例为例

    猫狗案例: 具体事务: 猫.狗 共性: 姓名.年龄.吃饭 分析:从具体到抽象 猫: 姓名.年龄--->成员变量 吃饭       ---> 成员方法 构造方法:无参.有参 狗: 姓名.年龄 ...

  9. Android带参数链接请求服务器

    public void taste() { //设默认值 SharedPreferences.Editor editor = this.getSharedPreferences("setti ...

  10. HDU 5211 筛法求约数

    给出n个数a1,a2...an,定义函数 f[i]=j,(i<j),表示aj mod ai=0 的最小j,其中j大于i,如果不存在这样的数,则f[i]=0 求n个数所有f[]值的和 先用筛法o( ...