Linux下使用curl库做HTTP GET、POST请求
linux下用c语言,可以使用curl库来实现相关http get、post之类的操作,看例子:
log.h
#ifndef _LOG_GLOBAL_H_
#define _LOG_GLOBAL_H_
#define LOG_DEBUG 1
#define LOG_GLOBAL_PATH “/media/sdcard/license_client/”
#define LOG_GLOBAL_FILE “license_client.log”
#define LOG_GLOBAL_MAX_LINE 100000
extern int InitLog();
extern int UninitLog();
extern void Log(const char *p_fmt, …);
extern void LogHex(char *pData, size_t size);
#endif /*_LOG_GLOBAL_H_*/
log.c
每10万行切换一个log文件名。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <malloc.h>
#include <stdarg.h>
#include <errno.h>
#include<sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
#include “log.h”
FILE *logGlobalFd = NULL;
unsigned int logGlobalLineNum = 0;
pthread_mutex_t logGlobalMutex;
int InitLog()
{
charlog[256];
#ifdef LOG_DEBUG
if(logGlobalFd){
return1; //already init.
}
mkdir(LOG_GLOBAL_PATH, 0755);
snprintf(log, sizeof(log), “%s/%s”, LOG_GLOBAL_PATH, LOG_GLOBAL_FILE);
logGlobalFd = fopen((char*)log, “a”);
if (!logGlobalFd){
printf(“%s=>%s(): failed to open log file (errno=%s)\n”, __FILE__, __FUNCTION__, strerror(errno));
return-1;
}
printf(“%s=>%s(): creat log file %s sucessfull!\n”, __FILE__, __FUNCTION__, log);
// init mutex
if (pthread_mutex_init(&logGlobalMutex, NULL) !=0){
fclose(logGlobalFd);
printf(“%s=>%s(): init mutex error!\n”, __FILE__, __FUNCTION__);
return-1;
}
#endif //LOG_DEBUG
return1;
}
int UninitLog()
{
#ifdef LOG_DEBUG
if(logGlobalFd){
fclose(logGlobalFd);
pthread_mutex_destroy(&logGlobalMutex);
}
#endif //LOG_DEBUG
return1;
}
static int LogNewLogFile()
{
chartmp[256];
chartmp2[256];
chardate[128];
time_t now;
struct tm ptm;
if (logGlobalFd)
{
fclose(logGlobalFd);
time(&now);
localtime_r(&now,&ptm);
strftime((char*)date, 128, “_%F_%T”, &ptm);
snprintf(tmp, sizeof(tmp), “%s/%s”, LOG_GLOBAL_PATH, LOG_GLOBAL_FILE);
snprintf(tmp2, sizeof(tmp2), “%s_%s.log”, tmp, date);
remove(tmp2);
rename(tmp, tmp2);
logGlobalFd = fopen((char*)tmp, “a”);
}
return1;
}
void Log(const char *p_fmt, …)
{
chardate[256];
time_t now;
struct tm ptm;
va_list ap;
#ifdef LOG_DEBUG
if (!logGlobalFd){
return;
}
pthread_mutex_lock(&logGlobalMutex);
time(&now); // Gets the system time
if (localtime_r(&now, &ptm))
{
strftime(date, sizeof (date), “%F %T”, &ptm);
fprintf(logGlobalFd, “%s “, date);
va_start(ap, p_fmt);
vfprintf(logGlobalFd, p_fmt, ap);
va_end(ap);
fflush(logGlobalFd);
logGlobalLineNum++;
if (logGlobalLineNum > LOG_GLOBAL_MAX_LINE){
LogNewLogFile();
logGlobalLineNum = 0;
}
}
pthread_mutex_unlock(&logGlobalMutex);
#endif //LOG_DEBUG
return;
}
void LogHex(char *pData, size_t size)
{
size_t i;
size_t c;
unsigned int width=0x10;
char lineStr[128];
for(i=0; i<size; i+= width) {
sprintf(lineStr, ” %8.8lX: \0″, (long)i);
/* show hex to the left */
for(c = 0; c < width; c++) {
if(i+c < size)
sprintf(lineStr+strlen(lineStr), “%02X \0”, pData[i+c]);
else
sprintf(lineStr+strlen(lineStr), ” \0″);
}
sprintf(lineStr+strlen(lineStr), ” \0″);
/* show data on the right */
for(c = 0; (c < width) && (i+c < size); c++) {
char x = (pData[i+c] >= 0x20 && pData[i+c] < 0x80) ? pData[i+c] : ‘.’;
sprintf(lineStr+strlen(lineStr), “%c\0”, x);
}
sprintf(lineStr+strlen(lineStr), “\n\0”);
Log(“DEBUG %s”, lineStr); /* newline */
}
Log(“DEBUG \n”); /* space line */
}
EasyCurl.h
基于网上代码修改而来的。
#ifndef __EASY_CURL_H__
#define __EASY_CURL_H__
#include <string>
#include <functional>
#include <tr1/memory>
#include <tr1/functional>
using std::string;
class IProgressCallback
{
public:
virtual bool OnProgressCallback(int nValue) = 0;
};
class EasyCurl
{
public:
EasyCurl(void);
~EasyCurl(void);
typedef std::tr1::function<void(int)> ProgressFunction;
public:
/// @brief HTTP POST请求
/// @param[in] strUrl 输入参数,请求的Url地址,如:https://www.baidu.com
/// @param[in] strParam 输入参数,使用格式”name=kandy&pwd=1234″
/// @param[out] strResponse 输出参数,返回的内容
/// @param[in] pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
/// @remark 返回是否Post成功
/// @return CURLE_OK,成功!其余失败
int http_post(const string & strUrl, const string & strParam, string & strResponse, const char * pCaPath = NULL);
/// @brief HTTPS GET请求
/// @param[in] strUrl 输入参数,请求的Url地址,如:https://www.baidu.com
/// @param[out] strResponse 输出参数,返回的内容
/// @param[in] pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
/// @remark 返回是否Post成功
/// @return CURLE_OK,成功!其余失败
int http_get(const string & strUrl, string & strResponse, const char * pCaPath = NULL);
/// @brief 文件下载
/// @param[in] url : 要下载文件的url地址
/// @param[in] outfilename : 下载文件指定的文件名
/// @remark
/// @return 返回0代表成功
int download_file(const string & strUrl, const string & strFile);
/// @brief 进度报告处理
/// @param[in] func : 函数地址
/// @remark
/// @return void
void set_progress_function(ProgressFunction func);
/// @brief 进度报告处理
/// @param[in] pCallback : 传入的对象
/// @remark 使用的类继承于IProgressCallback
/// @return void
void set_progress_callback(IProgressCallback *pCallback);
//
public:
void SetDebug(bool bDebug);
protected:
static int progress_callback(void *pParam, double dltotal, double dlnow, double ultotal, double ulnow);
private:
bool m_bDebug;
ProgressFunction m_updateProgress;
IProgressCallback *m_pHttpCallback;
};
#endif //__EASY_CURL_H__
EasyCurl.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
extern “C” {
#include”log.h”
}
#include “EasyCurl.h”
EasyCurl::EasyCurl(void)
: m_bDebug(false)
{
}
EasyCurl::~EasyCurl(void)
{
}
static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
switch(itype){
case CURLINFO_TEXT:
Log(“DEBUG %s => %s(): [TEXT], len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size, (long)size);
LogHex(pData, size);
break;
case CURLINFO_HEADER_IN:
Log(“DEBUG %s => %s(): [HEADER_IN], len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size, (long)size);
LogHex(pData, size);
break;
case CURLINFO_HEADER_OUT:
Log(“DEBUG %s => %s(): [HEADER_OUT], len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size, (long)size);
LogHex(pData, size);
break;
case CURLINFO_DATA_IN:
//Log(“DEBUG %s => %s(): [DATA_IN], len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size, (long)size);
//LogHex(pData, size);
break;
case CURLINFO_DATA_OUT:
//Log(“DEBUG %s => %s(): [DATA_OUT], len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size, (long)size);
//LogHex(pData, size);
break;
case CURLINFO_SSL_DATA_IN:
//Log(“DEBUG %s => %s(): [SSL_DATA_IN], len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size, (long)size);
//LogHex(pData, size);
break;
case CURLINFO_SSL_DATA_OUT:
//Log(“DEBUG %s => %s(): [SSL_DATA_OUT], len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size, (long)size);
//LogHex(pData, size);
break;
default:
Log(“ERROR %s => %s(): unknown itype: %d, len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, itype, (long)size, (long)size);
break;
}
return 0;
}
static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
string* str = dynamic_cast<string*>((string *)lpVoid);
if( NULL == str || NULL == buffer ) {
return -1;
}
char* pData = (char*)buffer;
str->append(pData, size * nmemb);
Log(“DEBUG %s => %s(): OnWriteData, len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size*nmemb, (long)size*nmemb);
LogHex((char *)buffer, size * nmemb);
return nmemb;
}
static size_t OnReadData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
string* str = dynamic_cast<string*>((string *)lpVoid);
if( NULL == str || NULL == buffer ) {
return -1;
}
char* pData = (char*)buffer;
str->append(pData, size * nmemb);
Log(“DEBUG %s => %s(): OnReadData, len: %10.10ld bytes (0x%8.8lx), context: \n”, __FILE__, __FUNCTION__, (long)size*nmemb, (long)size*nmemb);
LogHex((char *)buffer, size * nmemb);
return nmemb;
}
/* libcurl write callback function */
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
//CAN WRITE data to FILE.
//FILE* fp = NULL;
//fp = fopen(“c:\\test.dat”, “ab+”);// must be a, otherwise will recovery pre data.
//size_t nWrite = fwrite(ptr, nSize, nmemb, fp);
//fclose(fp);
//return nWrite;
}
//
int EasyCurl::progress_callback(void *pParam, double dltotal, double dlnow, double ultotal, double ulnow)
{
EasyCurl* pThis = (EasyCurl*)pParam;
int nPos = (int)((dlnow / dltotal) * 100);
if (pThis->m_pHttpCallback) {
pThis->m_pHttpCallback->OnProgressCallback(nPos);
}
if (pThis->m_updateProgress) {
pThis->m_updateProgress(nPos);
}
return 0;
}
//
string globalCurlStrSend;
int EasyCurl::http_post(const string & strUrl, const string & strParam, string & strResponse, const char * pCaPath)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl) {
return CURLE_FAILED_INIT;
}
if(m_bDebug) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strParam.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, OnReadData); //not used, only for PUT
globalCurlStrSend = “”;
curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&globalCurlStrSend);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); //for 302, redirect
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, “”);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
if(NULL == pCaPath) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); //not verify peer cert and peer host
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}
else {
//default is PEM, so needn’t to set, and can support DER.
//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,”PEM”);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); // wait 10 seconds to connect server.
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 100L); //wait 100 seconds to get content from server.
res = curl_easy_perform(curl);
if(res != CURLE_OK){ //CURLE_OK is 0
Log(“ERROR %s => %s(): curl_easy_perform() failed: %s\n”, __FILE__, __FUNCTION__, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return res;
}
long retcode = 0;
res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE , &retcode);
if(res != CURLE_OK){ //CURLE_OK is 0
Log(“ERROR %s => %s(): curl_easy_getinfo() failed: %s\n”, __FILE__, __FUNCTION__, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return res;
}
if(retcode == 200 || retcode == 302){ //success
Log(“DEBUG %s => %s(): curl_easy_getinfo() return code: %ld\n”, __FILE__, __FUNCTION__, retcode);
}else{ // can return content, but is not wanted content.
Log(“ERROR %s => %s(): curl_easy_getinfo() return code: %ld\n”, __FILE__, __FUNCTION__, retcode);
curl_easy_cleanup(curl);
return -1;
}
curl_easy_cleanup(curl);
return res;
}
//
int EasyCurl::http_get(const string & strUrl, string & strResponse, const char * pCaPath)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl) {
return CURLE_FAILED_INIT;
}
if(m_bDebug) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, OnReadData); //not used, only for PUT
globalCurlStrSend = “”;
curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&globalCurlStrSend);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); //for 302, redirect
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, “”);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
if(NULL == pCaPath) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); //not verify peer cert and peer host
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}
else {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 100L);
res = curl_easy_perform(curl);
if(res != CURLE_OK){ //CURLE_OK is 0
Log(“ERROR %s => %s(): curl_easy_perform() failed: %s\n”, __FILE__, __FUNCTION__, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return res;
}
long retcode = 0;
res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE , &retcode);
if(res != CURLE_OK){ //CURLE_OK is 0
Log(“ERROR %s => %s(): curl_easy_getinfo() failed: %s\n”, __FILE__, __FUNCTION__, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return res;
}
if(retcode == 200 || retcode == 302){ //success
Log(“DEBUG %s => %s(): curl_easy_getinfo() return code: %ld\n”, __FILE__, __FUNCTION__, retcode);
}else{ // can return content, but is not wanted content.
Log(“ERROR %s => %s(): curl_easy_getinfo() return code: %ld\n”, __FILE__, __FUNCTION__, retcode);
curl_easy_cleanup(curl);
return -1;
}
curl_easy_cleanup(curl);
return res;
}
//
int EasyCurl::download_file(const string & strUrl, const string & strFile)
{
FILE *fp;
//call curl_easy_init() to get easy interface type pointer.
CURL *curl = curl_easy_init();
if (curl) {
fp = fopen(strFile.c_str(), “wb”);
CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
if (res != CURLE_OK) {
fclose(fp);
curl_easy_cleanup(curl);
return -1;
}
res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
if (res != CURLE_OK) {
fclose(fp);
curl_easy_cleanup(curl);
return -1;
}
res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
if (res != CURLE_OK) {
fclose(fp);
curl_easy_cleanup(curl);
return -1;
}
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);//set progress function.
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this);
//start to run query.
res = curl_easy_perform(curl);
fclose(fp);
// Check for errors
if (res != CURLE_OK) {
curl_easy_cleanup(curl);
return -1;
}
curl_easy_cleanup(curl);// call curl_easy_cleanup() to release memory
}
return 0;
}
//
void EasyCurl::set_progress_function(ProgressFunction func)
{
m_updateProgress = func;
}
//
void EasyCurl::set_progress_callback(IProgressCallback *pCallback)
{
m_pHttpCallback = pCallback;
}
//
void EasyCurl::SetDebug(bool bDebug)
{
m_bDebug = bDebug;
}
main.cpp
调用测试:
int main(void)
{
//log init
InitLog();
//loop
EasyCurl easyCurl;
easyCurl.SetDebug(true);
for(;;){
Log(“DEBUG %s => %s(): Enter Main Loop. \n”, __FILE__, __FUNCTION__);
string strUrl = “http://www.baidu.com/”;
string strParam = “id=3435”;
string strResponse = “”; // return content will be saved in this string.
int rtn =easyCurl.http_post(strUrl, strParam, strResponse, NULL);
Log(“DEBUG %s => %s(): http_post return: %d\n”, __FILE__, __FUNCTION__, rtn);
sleep(5);
}
//log uninit
UninitLog();
return0;
}