libcurl

curl.se

libcurl is a free and easy-to-use client-side URL transfer library, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET and TFTP. libcurl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, HTTP/2, HTTP/3, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, Kerberos), file transfer resume, http proxy tunneling and more!

接口

easy接口是同步接口,lets you do single transfers with a synchronous and blocking function call。
multi接口异步接口,单个线程内允许多个同步传输。

在基于LibCurl的程序里,主要采用callback function (回调函数)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数,当满足条件时libcurl将调用用户的回调函数实现特定功能。

curl_global_init()初始化libcurl
curl_easy_init()获取easy interface型指针
curl_easy_setopt() 设置传输选项
curl_easy_perform() 阻塞直到完成传输任务
curl_easy_cleanup()释放内存

1. CURLcode curl_global_init(long flags)

这个函数只能用一次。(其实在调用curl_global_cleanup 函数后仍然可再用)

如果这个函数在curl_easy_init函数调用时还没调用,它讲由libcurl库自动调用, 所以多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用。

注意:虽然libcurl是线程安全的,但curl_global_init是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。

2. void curl_global_cleanup(void)

描述:在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。

注意:虽然libcurl是线程安全的,但curl_global_cleanup是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。

3. CURL *curl_easy_init( )

curl_easy_init用来初始化一个CURL的指针(有些像返回FILE类型的指针一样)。 相应的在调用结束时要用curl_easy_cleanup函数清理。
一般curl_easy_init意味着一个会话的开始,它会返回一个easy_handle(CURL*对象), 一般都用在easy系列的函数中。

4. void curl_easy_cleanup(CURL *handle);

这个调用用来结束一个会话.与curl_easy_init配合着用.

参数:CURL类型的指针。

5. CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter)

描述: 这个函数最重要了,几乎所有的curl 程序都要频繁的使用它。它告诉curl库,程序将有如何的行为。 比如要查看一个网页的html代码等。(这个函数有些像ioctl函数)

参数:
1)CURL类型的指针

2)各种CURLoption类型的选项.(都在curl.h库里有定义,man 也可以查看到)

3)parameter 既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量,取决于第二个参数。
CURLoption 这个参数的取值很多,具体的可以查看man手册。

6. CURLcode curl_easy_perform(CURL *handle);

在初始化CURL类型的指针 以及curl_easy_setopt完成后调用. 就像字面的意思所说perform就像是个舞台,让我们设置的option 运作起来。参数是CURL类型的指针。

7. struct curl_slist *curl_slist_append(struct curl_slist *list, const char *string)

curl_slist_append appends a string to a linked list of strings.

void curl_slist_free_all(struct curl_slist *list);

CRULOPT选项

curl_easy_setopt

curl_easy_setopt()用于设置http相关的参数。

  • CURLOPT_URL:设置访问URL
  • CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA

回调函数原型为: size_t function( void *ptr, size_t size, size_t nmemb, void *stream); 函数将在libcurl接收到数据后被调用,因此函数多做数据保存的功能,如处理下载文件。
CURLOPT_WRITEDATA 用于表明CURLOPT_WRITEFUNCTION函数中的stream指针的来源。

如果你没有通过CURLOPT_WRITEFUNCTION属性给easy handle设置回调函数,libcurl会提供一个默认的回调函数,它只是简单的将接收到的数据打印到标准输出。你也可以通过 CURLOPT_WRITEDATA属性给默认回调函数传递一个已经打开的文件指针,用于将数据输出到文件里。

  • CURLOPT_HEADERFUNCTION,CURLOPT_HEADERDATA

回调函数原型为 size_t function( void *ptr, size_t size,size_t nmemb, void *stream);

  • CURLOPT_READFUNCTION CURLOPT_READDATA

size_t function(void *ptr, size_t size, size_t nmemb,void *stream)

  • CURLOPT_NOPROGRESS,CURLOPT_PROGRESSFUNCTION,CURLOPT_PROGRESSDATA 数据传输进度

curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

CURLOPT_PROGRESSFUNCTION 指定的函数正常情况下每秒被libcurl调用一次,为了使CURLOPT_PROGRESSFUNCTION被调用,CURLOPT_NOPROGRESS必须被设置为0L。

int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);

  • CURLOPT_TIMEOUT,CURLOPT_CONNECTIONTIMEOUT设置传输超时和连接超时

  • CURLOPT_FOLLOWLOCATION 重定位URL

  • CURLOPT_RANGE, CURLOPT_RESUME_FROM 断点续传相关设置

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RANGE, char *range);

range应该是“X-Y”格式。CURLOPT_RANGE 指定char *参数传递给libcurl,用于指明http域的RANGE头域,例如:
表示头500个字节:bytes=0-499
表示第二个500字节:bytes=500-999
表示最后500个字节:bytes=-500
表示500字节以后的范围:bytes=500-
第一个和最后一个字节:bytes=0-0,-1
同时指定几个范围:bytes=500-600,601-999。

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RESUME_FROM, long from);

CURLOPT_RESUME_FROM 传递一个long参数给libcurl,指定你希望开始传递的 偏移量。

示例

#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>

CURL *curl_handle = NULL;
#define downLoad_url 	"https://pkg.go.dev/static/shared/gopher/package-search-700x300.jpeg"
#define downLoad_file 	"test.jpeg"

static size_t OnDownLoadFile(void* buffer,size_t size, size_t nmemb,void* fp)
{
   fwrite(buffer, size, nmemb, (FILE*)fp);
   fflush((FILE*)fp);
 
   return (size*nmemb);
}
 
 
static int my_progress_func(char *progress_data, double t, /* dltotal */ double d, /* dlnow */
        		double ultotal, double ulnow)
{
  printf("%s %g / %g (%g %%)\n", progress_data, d, t, d*100.0/t);
  return 0;
}

CURLcode download(char * strUrl, char *filepath)
{
    CURLcode res;
    char *progress_data = "* ";  
    FILE* fp = fopen(filepath,"wb+");
 
    curl_handle = curl_easy_init();
 
    /* send all data to this function */
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, OnDownLoadFile);
    /* we pass our 'chunk' struct to the callback function */
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)fp);
 
    curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L);  
    curl_easy_setopt(curl_handle, CURLOPT_PROGRESSFUNCTION, my_progress_func);  
    curl_easy_setopt(curl_handle, CURLOPT_PROGRESSDATA, progress_data);
 
    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
 
    curl_easy_setopt(curl_handle,CURLOPT_RESUME_FROM,0);  //从0字节开始下载
    /* 设置连接超时,单位:毫秒 */
    curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, 10000L);
    curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, 10000L);
    curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 3);
    curl_easy_setopt(curl_handle, CURLOPT_URL, downLoad_url);
 
 
    /* get it! */
    res = curl_easy_perform(curl_handle);
    /* check for errors */
    if (res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    }
 
    fclose(fp);
 
    curl_easy_cleanup(curl_handle);
    return res;
}

int main()
{
	download(downLoad_url, downLoad_file);
}
int gatewayregister()
{
    CURL *curl_handle;
    CURLcode res;
    char info[100];
    struct curl_slist *list = NULL;
    
    sprintf(info, "{\"mac\":\"%s\",\n\"version\":\"0.5\"}", g_mac);
    curl_global_init(CURL_GLOBAL_ALL);
    curl_handle = curl_easy_init();

    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
    curl_easy_setopt(curl_handle, CURLOPT_POST,1);
    
	//curl_easy_setopt(curl_handle,CURLOPT_VERBOSE,1); 

    curl_easy_setopt(curl_handle, CURLOPT_URL, "https://123.233.201.69:8990//gatewayregister");
    
    list = curl_slist_append(list, "accept: */*");
    list = curl_slist_append(list, "Content-Type: application/json");

    curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list);
    curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, info);

    res = curl_easy_perform(curl_handle);

    if(res != CURLE_OK)
    {
        MYLOG_ERROR("curl_easy_perform() failed: %s\n",
        curl_easy_strerror(res));
        curl_easy_cleanup(curl_handle);
        curl_slist_free_all(list);
        curl_global_cleanup();        
        return -1;
    }
    else
    {
        MYLOG_INFO("Gateway register success!\n");     
        curl_easy_cleanup(curl_handle);
        curl_slist_free_all(list);
        curl_global_cleanup();   
        return 0;
    }
}
int updatefile(const char* filepath)
{
    MYLOG_INFO("begin to upload file:%s", filepath);
    if (!filepath)
    {
        MYLOG_ERROR("The filepath is null");
        return -1;
    }
    

    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL *hCurl = curl_easy_init();

    if(hCurl != NULL)
    {
        struct curl_slist *pOptionList = NULL;
        pOptionList = curl_slist_append(pOptionList, "Expect:");
        curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, pOptionList);

        struct curl_httppost* pFormPost = NULL;
        struct curl_httppost* pLastElem = NULL;

        curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, "file", CURLFORM_FILE, 
            filepath, CURLFORM_CONTENTTYPE, "text/plain", CURLFORM_END);

		curl_easy_setopt(hCurl,CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(hCurl,CURLOPT_SSL_VERIFYHOST, 0);
        curl_easy_setopt(hCurl, CURLOPT_HTTPPOST, pFormPost);
        curl_easy_setopt(hCurl, CURLOPT_URL, HTTP_UPLOAD_URL);

        CURLcode res = curl_easy_perform(hCurl);
        if(res != CURLE_OK)
        {
            MYLOG_ERROR("upload file error");
        }
        curl_formfree(pFormPost);
        curl_easy_cleanup(hCurl);
    }

    curl_global_cleanup();
    return 0;
}

参考:

  1. HTTP多线程下载+断点续传
posted @ 2016-08-22 22:05  yuxi_o  阅读(536)  评论(0编辑  收藏  举报