libcurl 下载上传
近来一个新的项目需要使用到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 下载上传的更多相关文章
- WP8.1 Study17:网络之后台下载/上传及HttpClient
一.后台下载/上传 1.简介 使用BackgroundTransferGroup可以十分方便操作上传及下载文件,BackgroundDownloader和BackgroundUploader类中的方法 ...
- https 协议下服务器根据网络地址下载上传文件问题
https 协议下服务器根据网络地址下载上传文件遇到(PKIX:unable to find valid certification path to requested target 的问题) 使用h ...
- git下载/上传文件提示:git did not exit cleanly
问题:git操作下载/上传文件,提示信息如下 TortoiseGit-git did not exit cleanly (exit code 1) TortoiseGit-git did not ex ...
- 亚马逊S3下载上传文件
引用网址: http://www.jxtobo.com/27697.html 下载 CloudBerry Explorer http://www.cloudberrylab.com/download- ...
- C#FTP操作类含下载上传删除获取目录文件及子目录列表等等
ftp登陆格式 : ftp://[帐号]:[密码]@[IP]:[端口] ftp://用户名:密码@FTP服务器IP或域名:FTP命令端口/路径/文件名 直接上代码吧,根据需要选择函数,可根据业务自己 ...
- C语言 HTTP上传文件-利用libcurl库上传文件
原文 http://justwinit.cn/post/7626/ 通常情况下,一般很少使用C语言来直接上传文件,但是遇到使用C语言编程实现文件上传时,该怎么做呢? 借助开源的libcurl库,我们 ...
- 一行代码实现Okhttp,Retrofit,Glide下载上传进度监听
https://mp.weixin.qq.com/s/bopDUFMB7EiK-MhLc3KDXQ essyan 鸿洋 2017-06-29 本文作者 本文由jessyan投稿. jessyan的博客 ...
- vc libcurl 模拟上传文件
http://www.cnblogs.com/killbit/p/5393301.html 附上这篇文章,因为当时就已经想到了模拟上传,但是因为时间关系,所以就直接用PHP写了.现在改进一下,用VC+ ...
- Ubuntu 16.04通过Trickle限制某个软件的下载/上传速度
在Linux下没有Windows使用360那样去限制某个软件的速度. 但是通过Trickle可以设置某个软件的网速,但是前提是通过Trickle命令连带启动这个软件才可以,不能中途去设置. 比如现在很 ...
随机推荐
- mysql备份数据库
需求: 1,每天4点备份mysql数据: 2,为节省空间,删除超过3个月的所有备份数据: 3,删除超过7天的备份数据,保留3个月里的 10号 20号 30号的备份数据: #创建shell文件 vim ...
- Angular过滤器 自定义及使用方法
首先设置自定义过滤器. 定义模块名:angular .module('myApp') .filter('filterName',function(){ return function(要过滤的对象,参 ...
- QueryPerformanceFrequency使用方法--Windows高精度定时计数
在多核心或多处理器的计算机上.特别是在支持CPU频率动态调整的计算机上,windows系统下的QueryPerformanceFrequency()获取HPET(假设存在)的频率,而QueryPerf ...
- SpringMVC 学习笔记(一) Hello World
springMVC概述: Spring MVC 是眼下最主流的MVC 框架之中的一个 Spring MVC 通过一套 MVC 注解.让 POJO 成为处理请 求的控制器,而无须实现不论什么接口. 支持 ...
- Linux的进程优先级-邹立巍
http://liwei.life/2016/04/07/linux%E7%9A%84%E8%BF%9B%E7%A8%8B%E4%BC%98%E5%85%88%E7%BA%A7/
- [转] tomcat结合nginx使用小结
相信很多人都听过nginx,这个小巧的东西慢慢地在吞食apache和IIS的份额.那究竟它有什么作用呢?可能很多人未必了解. 说到反向代理,可能很多人都听说,但具体什么是反向代理,很多人估计就不清楚了 ...
- Linux入门基础教程
转载自:http://www.centoscn.com/CentOS/2015/0528/5555.html 1. 1 Linux操作系统简介 Linux是一套免费使用和自由传播的类Unix ...
- eclipse如何运行maven项目
不然启动tomcat会提示spring的类找不到
- Android开发手记(23) Notification
有时候,我们需要应用程序在状态内显示一些通知信息,这时我们就需要使用Notification来完成这一工作.也许我们会想到以前经常使用的Toast来通知用户.虽然Notification与Toast都 ...
- linux command cp.
Examples cp file1.txt newdir Copies the file1.txt in the current directory to the newdir subdirector ...