常规信息GET请求:
CURL *curl;
curl = curl_easy_init();
url = "https://www.xxx.com/time?hmac=xx&id=xx";
curl_easy_setopt(curl, CURLOPT_CURL, url);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); //http 0L
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // http 0L
curl_easy_setopt(curl, CURLOPT_CAINFO, "/home/app/ca/myca.crt"); //HTTP 没有这句
curl_easy_perform(curl);
curl_easy_clearup(curl);
这样,请求就完成了。 那么后台返回了什么结果,怎么办。
1,curl_easy_perform在执行时,会输出请求和结果的完整文本,所以可以通过单写一个程序,执行curl,在调用程序中,通过popen执行这个程序,获取程序执行的输出,可以从输出中解析出结果。(不是常规用法)。
2,常规用法:
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &resp_data_handle);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); //下面会说到
static char g_resp_data[4096] = {};
static int g_resp_data_offset = 0;
static int resp_data_handle(void *ptr, size_t size, size_t nmemb, void* stream) {
int this_size = size * nmemb;
if(g_resp_data_offset + this_size < 4096 ){
memcpy(g_resp_data+g_resp_data_offset, ptr, this_size);
g_resp_data_offset += this_size;}
return this_size; }
首先,resp_data_handle 这个函数是注册给curl的回调函数,有数据返回,就会调用handle函数,所以接收到的数据不是全部的数据,需要自己在handle中拼接。这样,我们就可以在从curl_easy_clearup后g_resp_data得到返回结果。
其次,CURLOPT_WRITEDATA设置的指针,如果同时设置了write function函数,则这个指针会作为function的第四个参数,传递给write function, 在function中,自己对这个指针进行操作, 如果不需要,就设置成NUL。如果没有设置 write function, WRITEDATA设置一个FILE *的文件指针, 那么,默认的回调函数,会把返回数据写入该文件中去。
上传文件
fp = fopen(filename, "rb");
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
rewind(fp);
curl_easy_setopt(curl, CURLOPT_PUT, 1L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);//s
curl_easy_setopt(curl, CURLOPT_READFUNCTION, &read_file);
curl_easy_setopt(curl, CURLOPT_READDATA, fp);
curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size);
相比GET请求,多方法设置,read函数。
static size_t read_file(void *buff, size_t size, size_t nmemb, void* userpf){
len = fread(buff, size, nmemb, (FILE *)userpf);
return len; }
自己从文件中把数据读到buff中。
对于上传的文件,如果自身是加密的,可以使用HTTP协议。
下载
fp = fopen(filename, "wb");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &downloadPackage);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);//设置为false,有进度,下面设置进度处理函数
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressFunc);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);//跟踪重定向
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);//在多线程处理场景下,会忽略signals对应的处理函数
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 30L);//和limit合在一起使用,在30s内,如果还没有接收到一个字节,就认为速度太慢,abort。
static int g_downloaded_size = 0;//在知道int不会被溢出的情况下。这个值可以定义在userdata的结构体里,在回调时,和pf一起传进去, 就不需要定义成一个全局的。
static int downloadPackage(void *ptr, int size, int nmemb, void *userdata){
int written_size = fwrite(ptr, size, nmemb, (FILE *)userdata);
g_downloaded_size += size*nmemb;
return written_size; }
static int progressFunc(void *ptr, double total_to_download, double now_downloaded, double total_to_upload, double now_uploaded ){
if(total_to_download > 0)
downloaded_progress = (int)(now_downloaded/total_to_download * 100) ; }
perform执行完成后, g_downloaded_size就是我们自己记录的下载size, 再调用
double curl_downloaded_size = 0.0;
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curl_downloaded_size);
if(g_downloaded_size == (int)curl_downloaded_size) 认为下载成功。
这就是一个简单的文件下载过程,下载完成之后,还可以通过md5sum,和线上进行比对,判断文件和服务器一致。