您的位置:首页 > 理论基础 > 计算机网络

使用CURL实现http文件下载加一个多任务的封装.

2012-04-19 21:09 961 查看
What I write, what I lose.

Mark下.

主要是使用CURL实现http文件下载,

在此基础上做一个多任务的封装. 附带md5检测.

头文件:

#define HTTPTASKE_OK            0
#define HTTPTASKE_ERROR         1

#define TASKID                  int

typedef enum
{
STATUS_BASE                     = 0,

STATUS_IDLE,
STATUS_RUNNING,
STATUS_FINISHED_OK,
STATUS_FINISHED_ERROR,
}HttpTaskStatus_e;

int httptask_init(void);
int httptask_deinit(void);

int httptask_addfiletask(const char* url_s, int timeout_s,
const char* filename_s,
const char* checkmd5sum_s, long checksize_s);
int httptask_addbuffertask(const char* url_s, int timeout_s,
char* buffer_s, long size_buffer_s,
const char* checkmd5sum_s, long checksize_s);

int httptask_run(void);
int httptask_asynrun(void);

int httptask_getitemstatus(int i, HttpTaskStatus_e* status_e, int* percent);
int httptask_getstatus(HttpTaskStatus_e* status_e, int* percent);


  实现文件:

#include <stdio.h>
#include <string.h>
#include <pthread.h>

#include "common_debug.inc.h"
#include "curl/curl.h"
#include "httptask.h"
#include "md5chk.h"

#define u_strcpy(dest, len, src) strncpy(dest, src, len-1)

#define HTTPTASK_LEN_URL        1024
#define HTTPTASK_LEN_FILENAME   1024
#define HTTPTASK_LEN_MD5SUM     36
#define HTTPTASK_LEN_MD5        20
#define HTTPTASK_NUM_MAXTASK    10

struct _HttpTaskItem
{
//
char url[HTTPTASK_LEN_URL];
int timeout;

char filename[HTTPTASK_LEN_FILENAME];
bool filemode;

char* buffer;
long size_buffer;

//
char check_md5sum[HTTPTASK_LEN_MD5SUM];
long check_size;

//
double dltotal;
double dlnow;
FILE* fp;
long index_buffer;

//md5 count about.
MD5_CTX md5ctx;
unsigned char md5ori[HTTPTASK_LEN_MD5];
size_t dlcount;

//Status about.
HttpTaskStatus_e item_status_e;
double percent;
double base_percent;
};
typedef struct _HttpTaskItem HttpTaskItem;

struct _HttpTaskItemSet
{
int num;
HttpTaskItem httptask[HTTPTASK_NUM_MAXTASK];

HttpTaskStatus_e status_e;
double percent;
};
typedef struct _HttpTaskItemSet HttpTaskItemSet;

HttpTaskItemSet gs_httptaskset = {0};

int httptask_init(void)
{
int ret = HTTPTASKE_OK;

HttpTaskItemSet* httptaskset = &gs_httptaskset;
httptaskset->num = 0;
int i = 0;
for(i=0; i<HTTPTASK_NUM_MAXTASK; i++)
{
HttpTaskItem* httptask = &(httptaskset->httptask[i]);
httptask = httptask;
//httptaskitem_init(httptask);
}
memset(httptaskset, 0, sizeof(HttpTaskItemSet));

httptaskset->status_e = STATUS_IDLE;

return ret;
}

int httptask_deinit(void)
{
int ret = HTTPTASKE_OK;

HttpTaskItemSet* httptaskset = &gs_httptaskset;
httptaskset->num = 0;
int i = 0;
for(i=0; i<HTTPTASK_NUM_MAXTASK; i++)
{
HttpTaskItem* httptask = &(httptaskset->httptask[i]);
httptask = httptask;
//httptaskitem_deinit(httptask);
}
memset(httptaskset, 0, sizeof(HttpTaskItemSet));

httptaskset->status_e = STATUS_IDLE;

return ret;
}

int httptask_addfiletask(const char* url_s, int timeout_s,
const char* filename_s,
const char* checkmd5sum_s, long checksize_s)
{
int ret = HTTPTASKE_OK;

HttpTaskItemSet* httptaskset = &gs_httptaskset;
int index = httptaskset->num;
if(index >= HTTPTASK_NUM_MAXTASK)
{
DBGPRINTF_ERROR("Add File task error.\n");
ret = HTTPTASKE_ERROR;
return ret;
}
(httptaskset->num) ++ ;
HttpTaskItem* httptask = &(httptaskset->httptask[index]);
u_strcpy(httptask->url, HTTPTASK_LEN_URL, url_s);
httptask->timeout = timeout_s;
httptask->filemode = false;
u_strcpy(httptask->filename, HTTPTASK_LEN_FILENAME, filename_s);
httptask->filemode = true;

if(checkmd5sum_s != NULL)
{
u_strcpy(httptask->check_md5sum, HTTPTASK_LEN_MD5SUM, checkmd5sum_s);
}
httptask->check_size = checksize_s;

httptask->item_status_e = STATUS_IDLE;
httptask->percent = -1;

DBGPRINTF_DEBUG("Add File task OK.\n");

return ret;
}

int httptask_addbuffertask(const char* url_s, int timeout_s,
char* buffer_s, long size_buffer_s,
const char* checkmd5sum_s, long checksize_s)
{
int ret = HTTPTASKE_OK;

HttpTaskItemSet* httptaskset = &gs_httptaskset;
int index = httptaskset->num;
if(index >= HTTPTASK_NUM_MAXTASK)
{
DBGPRINTF_ERROR("Add File task error.\n");
ret = HTTPTASKE_ERROR;
return ret;
}
(httptaskset->num) ++ ;
HttpTaskItem* httptask = &(httptaskset->httptask[index]);
u_strcpy(httptask->url, HTTPTASK_LEN_URL, url_s);
httptask->timeout = timeout_s;
httptask->filemode = false;
httptask->buffer = buffer_s;
httptask->size_buffer = size_buffer_s;

if(checkmd5sum_s != NULL)
{
u_strcpy(httptask->check_md5sum, HTTPTASK_LEN_MD5SUM, checkmd5sum_s);
}
httptask->check_size = checksize_s;

httptask->item_status_e = STATUS_IDLE;
httptask->percent = -1;

DBGPRINTF_DEBUG("Add Buffer task OK.\n");

return ret;
}

static int httptask_perform(HttpTaskItemSet* httptaskset);

int httptask_run(void)
{
int ret = HTTPTASKE_OK;

DBGPRINTF_INFO("HttpTask run.\n");

HttpTaskItemSet* httptaskset = &(gs_httptaskset);
ret = httptask_perform(httptaskset);

DBGPRINTF_INFO("HttpTask run finished.\n");

return ret;
}

void* func_httptaskperform(void* arg)
{
HttpTaskItemSet* httptaskset = (HttpTaskItemSet*)arg;
httptask_perform(httptaskset);

return NULL;
}

int httptask_asynrun(void)
{
int ret = HTTPTASKE_OK;

DBGPRINTF_INFO("HttpTask Asyn run.\n");

HttpTaskItemSet* httptaskset = &(gs_httptaskset);

pthread_t pid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int ret_pthread = pthread_create(&pid, &attr, func_httptaskperform, httptaskset);
if(ret_pthread != 0)
{
DBGPRINTF_ERROR("HttpTask : AsyncRun create pthread error.\n");
ret = HTTPTASKE_ERROR;
}

DBGPRINTF_INFO("HttpTask Asyn run finished.\n");

return ret;
}

int httptask_getitemstatus(int i, HttpTaskStatus_e* status_e, int* percent)
{
int ret = HTTPTASKE_OK;

HttpTaskItemSet* httptaskset = &(gs_httptaskset);
HttpTaskItem* httptask = &(httptaskset->httptask[i]);
*status_e = httptask->item_status_e;
*percent = (httptask->percent>=0.0)?(int)(httptask->percent * 100.0 + 0.5):-1;

return ret;
}

int httptask_getstatus(HttpTaskStatus_e* status_e, int* percent)
{
int ret = HTTPTASKE_OK;

HttpTaskItemSet* httptaskset = &(gs_httptaskset);
*status_e = httptaskset->status_e;
*percent = (httptaskset->percent>=0.0)?(int)(httptaskset->percent * 100.0 + 0.5):-1;

return ret;
}

static size_t HttpWriteContentToFp(char *buffer, size_t size, size_t nitems, void *outstream);
static size_t HttpWriteContentToBuffer(char *buffer, size_t size, size_t nitems, void *outstream);
static int WriteProgress(void* p, double dltotal, double dlnow, double ultotal,double ulnow);

int httptask_countbasepercent(HttpTaskItemSet* httptaskset);
int httptaskitem_addrecvedsize(HttpTaskItem* httptask, size_t size_recv);
int httptaskitem_updatepercent(HttpTaskItem* httptask, double percent);

int httptask_perform(HttpTaskItemSet* httptaskset)
{
int ret = HTTPTASKE_OK;

DBGPRINTF_DEBUG("HttpTask perform.\n");

httptask_countbasepercent(httptaskset);

httptaskset->status_e = STATUS_RUNNING;
int i = 0;
bool finishedok = true;
for(i=0; i<httptaskset->num; i++)
{
DBGPRINTF_DEBUG("HttpTask perform : %d.\n", i+1);

HttpTaskItem* httptask = &(httptaskset->httptask[i]);
httptask->item_status_e = STATUS_RUNNING;
httptask->percent = 0.0;

httptask->dlcount = 0;

//Count md5.
if((httptask->check_md5sum!=NULL) && (strlen(httptask->check_md5sum)>0))
{
MD5Init(&(httptask->md5ctx));
}

//Create CURL handle.
CURLcode ret_curl = CURLE_OK;
CURL* curl = curl_easy_init();
if(curl == NULL)
{
DBGPRINTF_ERROR("curl_easy_init error.\n");
httptask->item_status_e = STATUS_FINISHED_ERROR;
finishedok = false;
break;
}

/*Set url.*/
curl_easy_setopt(curl, CURLOPT_URL, httptask->url);
/*Timeout set.*/
if(httptask->timeout > 0)
{
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, httptask->timeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, httptask->timeout);
}

/*Low speed.*/
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 20L);

/*Set debug on.*/
#ifdef HTTPPT_DEBUG
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
#endif

/*Set progress.*/
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, WriteProgress);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, httptask);

/*Set callback.*/
//鍖哄垎璁剧疆 鍐機ontent 鍒版枃浠?or 鍒癰uffer.
if(httptask->filemode)
{
FILE* fp = fopen(httptask->filename, "w");
if(fp == NULL)
{
DBGPRINTF_ERROR("Open file to write failed.[%s].\n", httptask->filename);
httptask->item_status_e = STATUS_FINISHED_ERROR;
finishedok = false;
/* always cleanup */
curl_easy_cleanup(curl);
break;
}
httptask->fp = fp;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HttpWriteContentToFp);
}
else
{
httptask->index_buffer = 0;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HttpWriteContentToBuffer);
}
curl_easy_setopt(curl, CURLOPT_WRITEDATA, httptask);

/* Perform the request, res will get the return code */
ret_curl = curl_easy_perform(curl);

if((httptask->filemode) && (httptask->fp != NULL))
{
fclose(httptask->fp);
httptask->fp = NULL;
}

/* always cleanup */
curl_easy_cleanup(curl);

/* Check return value after curl_easy_perform. */
if(ret_curl != CURLE_OK)
{
DBGPRINTF_ERROR("[CURL]%s.\n", curl_easy_strerror(ret_curl));
httptask->item_status_e = STATUS_FINISHED_ERROR;
finishedok = false;
break;
}

/*Check md5 checksum.*/
if((httptask->check_md5sum!=NULL) && (strlen(httptask->check_md5sum)>0))
{
MD5Final(httptask->md5ori, &(httptask->md5ctx));
char count_md5sum[HTTPTASK_LEN_MD5SUM] = {0};
int i = 0;
char tmp[4] = {0};
for(i=0; i<16; i++)
{
memset(tmp, 0, 4);
snprintf(tmp, 4, "%02x", httptask->md5ori[i]);
memcpy(count_md5sum+i*2, tmp, 2);
}
DBGPRINTF_DEBUG("count_md5sum=%s.\n", count_md5sum);
DBGPRINTF_DEBUG("check_md5sum=%s.\n", httptask->check_md5sum);

if(strcasecmp(httptask->check_md5sum, count_md5sum) == 0)
{
DBGPRINTF_DEBUG("Md5 check OK.\n");
}
else
{
DBGPRINTF_ERROR("Md5 check ERROR.\n");
httptask->item_status_e = STATUS_FINISHED_ERROR;
finishedok = false;
break;
}
}

/*Check downloaded size.*/
if(httptask->check_size!=0)
{
size_t dlcount          = (size_t)(httptask->dlcount);
size_t check_size       = (size_t)(httptask->check_size);
size_t dlnow            = (size_t)(httptask->dlnow);
size_t dltotal          = (size_t)(httptask->dltotal);

if( (dltotal != 0) &&
!( (dlcount==check_size) && (dlnow==dltotal) && (dlnow==dlcount) ) )
{
DBGPRINTF_ERROR("Size check ERROR., [checksize:%ld, dlcount:%u, dlnow:%lf, dltotal:%lf].\n",
httptask->check_size, httptask->dlcount, httptask->dlnow, httptask->dltotal);
httptask->item_status_e = STATUS_FINISHED_ERROR;
finishedok = false;
break;
}

if( (httptask->dltotal == 0) &&
!( (dlcount==check_size) && (dlnow==dlcount) ) )
{
DBGPRINTF_ERROR("Size check ERROR., [checksize:%ld, dlcount:%u, dlnow:%lf, dltotal:%lf].\n",
httptask->check_size, httptask->dlcount, httptask->dlnow, httptask->dltotal);
httptask->item_status_e = STATUS_FINISHED_ERROR;
finishedok = false;
break;
}
}

httptask->percent = 1;
}

httptaskset->status_e = finishedok?STATUS_FINISHED_OK:STATUS_FINISHED_ERROR;

return ret;
}

size_t HttpWriteContentToFp(char *buffer, size_t size, size_t nitems, void *outstream)
{
HttpTaskItem* httptask = (HttpTaskItem*)outstream;

//DBGPRINTF_DEBUG("Receive data : %u .\n", nitems);
FILE* fp = httptask->fp;
size_t size_recv = fwrite(buffer, size, nitems, fp);
httptask->dlcount += size_recv;
httptaskitem_addrecvedsize(httptask, size_recv);

//Count md5.
if((httptask->check_md5sum!=NULL) && (strlen(httptask->check_md5sum)>0) && (size_recv > 0))
{
MD5Update(&(httptask->md5ctx), (unsigned char*)buffer, size_recv);
}

return size_recv;
}

size_t HttpWriteContentToBuffer(char *buffer, size_t size, size_t nitems, void *outstream)
{
HttpTaskItem* httptask = (HttpTaskItem*)outstream;

//DBGPRINTF_DEBUG("Receive data : %u .\n", nitems);
long* index = &(httptask->index_buffer);
size_t size_recv = 0;
if((long)(size*nitems) <= httptask->size_buffer - *index)
{
size_recv = size*nitems;
memcpy(httptask->buffer + *index, buffer, size*nitems);
*index += size*nitems;
}
else
{
DBGPRINTF_ERROR("Buffer not enought to store downloaded content.\n");
size_recv = 0 ;
}

httptask->dlcount += size_recv;
httptaskitem_addrecvedsize(httptask, size_recv);

//Count md5.
if((httptask->check_md5sum!=NULL) && (strlen(httptask->check_md5sum)>0) && (size_recv > 0))
{
MD5Update(&(httptask->md5ctx), (unsigned char*)buffer, size_recv);
}

return size_recv;
}

int WriteProgress(void* p, double dltotal, double dlnow, double ultotal,double ulnow)
{
HttpTaskItem* httptask = (HttpTaskItem*)p;

//DBGPRINTF_DEBUG("WriteProgress : %lf, %lf .\n", dlnow, dltotal);
httptask->dltotal = dltotal;
httptask->dlnow = dlnow;

if((httptask->dlnow > 0) && (httptask->dlnow != -1))
{
//double pre_percent = httptask->percent;
httptask->percent = httptask->dlnow / httptask->dltotal;
//double add_percent = httptask->percent - pre_percent;
httptaskitem_updatepercent(httptask, httptask->percent);
}

return 0;
}

int httptaskitem_addrecvedsize(HttpTaskItem* httptask, size_t size_recv)
{
int ret = HTTPTASKE_OK;

return ret;
}

int httptaskitem_updatepercent(HttpTaskItem* httptask, double percent)
{
int ret = HTTPTASKE_OK;
percent = percent;
HttpTaskItemSet* httptaskset = &gs_httptaskset;
httptaskset->percent = 0.0;
int i = 0;
for(i=0; i<httptaskset->num; i++)
{
HttpTaskItem* httptask = &(httptaskset->httptask[i]);
if(httptask->percent>=0.0)
{
httptaskset->percent += httptask->percent * httptask->base_percent ;
}
}

return ret;
}

int httptask_countbasepercent(HttpTaskItemSet* httptaskset)
{
int ret = HTTPTASKE_OK;

int i = 0;
bool sizeset = true;
long totalsize = 0;
for(i=0; i<httptaskset->num; i++)
{
HttpTaskItem* httptask = &(httptaskset->httptask[i]);
if(httptask->check_size <= 0)
{
sizeset = false;
break;
}
totalsize += httptask->check_size;
}

for(i=0; i<httptaskset->num; i++)
{
HttpTaskItem* httptask = &(httptaskset->httptask[i]);
httptask->percent = 0;
if(sizeset)
{
httptask->base_percent = double(httptask->check_size) / double(totalsize);
}
else
{
httptask->base_percent = 1 / httptaskset->num;
}
}

return ret;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐