1 摘要
1.1 平台
运行平台:君正x2000
libcurl版本:7.68.0,通过buildroot编译生成。
编译器:mips-linux-gnu-gcc (gcc version 7.2.0 (Ingenic r4.0.0-gcc720 2018.02-28))
编译主机:ubuntu 18.04
1.2 功能
http通信(1)
1.1最少的代码实现http访问百度,这个示例将通过get方法访问百度,并将百度返回的结果存入data.html文件中。
http通信(2)
2.1 增加获取libcurl库信息
2.2 增加打印打印http响应head数据
2.3 增加使能版本库调试功能
2 打印版本库信息
static void print_version_info(void)
{
curl_version_info_data *version_info = curl_version_info(CURLVERSION_NOW);
printf("version:%s\n", version_info->version);
printf("host:%s\n", version_info->host);
printf("ssl_version:%s\n", version_info->ssl_version);
}
int main()
{
........
........
/*
* 打印本本库信息
*/
print_version_info();
....
....
return 0;
}
2.1 执行结果
# ./test
version:7.68.0
host:mipsel-buildroot-linux-gnu
ssl_version:OpenSSL/1.1.1g
3 增加调试功能
CURLOPT_VERBOSE选项非常有用,当我们在调试嵌入式系统的时候没有wireshark等抓包工具,打开CURLOPT_VERBOSE选项可以看到libcurl的执行过程
/*
* 设置libcurl的选项,没有指定http访问方法,libcurl默认使用get方法
*/
curl_easy_setopt(easy_handle, CURLOPT_URL, "http://www.baidu.com");
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, baidu_get_test_cb);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, fp);
/*
* 增加调试功能,可以查看libcurl的执行过程
*/
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE, 1);
3.1 执行结果
# ./test
version:7.68.0
host:mipsel-buildroot-linux-gnu
ssl_version:OpenSSL/1.1.1g
* Trying 110.242.68.3:80...
* TCP_NODELAY set
* Connected to www.baidu.com (110.242.68.3) port 80 (#0)
> GET / HTTP/1.1
Host: www.baidu.com
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: no-cache
< Connection: keep-alive
< Content-Length: 14615
< Content-Type: text/html
< Date: Sat, 20 Mar 2021 03:02:49 GMT
< P3p: CP=" OTI DSP COR IVA OUR IND COM "
< P3p: CP=" OTI DSP COR IVA OUR IND COM "
< Pragma: no-cache
< Server: BWS/1.1
< Set-Cookie: BAIDUID=948BD633A8A66E61E08D2D51C124E8F2:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
< Set-Cookie: BIDUPSID=948BD633A8A66E61E08D2D51C124E8F2; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
< Set-Cookie: PSTM=1616209369; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
< Set-Cookie: BAIDUID=948BD633A8A66E611382AE5374C312B9:FG=1; max-age=31536000; expires=Sun, 20-Mar-22 03:02:49 GMT; domain=.baidu.com; path=/; version=1; comment=bd
< Traceid: 161620936935453114985383216040678206036
< Vary: Accept-Encoding
< X-Ua-Compatible: IE=Edge,chrome=1
<
* Connection #0 to host www.baidu.com left intact
4 选项名:CURLOPT_HEADERFUNCTION
CURLOPT_WRITEFUNCTION 用于接收http get返回的数据部分信息,如果想接收http get返回的头部信息,可以使用CURLOPT_HEADERFUNCTION选项
4.1 原型
#include <curl/curl.h>
size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata);
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HEADERFUNCTION, header_callback);
4.2 描述
传递一个上面原型中类型的回调函数指针。
当libcurl接收头数据的时候这个函数被调用。每一个头部信息,都会调用一次这个函数并且只有完整的头才会产生回调。使用这个函数去解析头部是非常简单的。buffer指针指向被接被接收的数据。nitems是数据的大小,size总是1。不要认为一行头信息是以'\0'结束的。
userdata指针是你通过CURLOPT_HEADERDATA选项设置的。
回调函数必须返回实际被处理的字节个数,如果回调函数返回的和传进来的字节数不同,libcurl将会产生一个错误信号。这将会引起传输终止,并且执行函数将会返回一个CURLE_WRITE_ERROR错误。
传入到回到函数的完整的http可能多大CURL_MAX_HTTP_HEADER (100K)字节数,这其中也包括最后一行含有的终止符。
重要的是要注意,在发起请求后,将为收到的所有响应的头调用回调函数,而不仅仅是最终响应。这包括在身份验证协商期间发生的所有响应。如果你只需要对最终响应的头进行操作,那么您将需要自己在回调中收集头信息,并使用HTTP状态行来划分响应边界。
对于HTTP传输,状态行和响应主体前面的空行都包含在报头中,并传递给此函数。
5 代码实实现
Makefile
LIBS=-L../../../buildroot/output/target/usr/lib -lpthread -lz -lcurl -lcrypto -lssl -lcjson
CC_FLAG=-Wall -I../../../buildroot/output/staging/usr/include
SRC=curl_test.c
CC=mips-linux-gnu-gcc
test : $(SRC)
$(CC) $< $(LIBS) $(CC_FLAG) -O2 -o $@
cp -v $@ ~/nfs
.PHONY : clean
clean :
rm -rf test
curl_test.c
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
static void baidu_get_test(void);
static void print_version_info(void);
int main()
{
CURLcode code;
code = curl_global_init(CURL_GLOBAL_ALL);
if(CURLE_OK != code) {
printf("curl init Err\n");
return -1;
}
/*
* 打印本本库信息
*/
print_version_info();
/*
* get 方法访问百度并获取数据
*/
baidu_get_test();
curl_global_cleanup();
return 0;
}
static size_t baidu_get_test_cb(void *buffer, size_t size, size_t nmemb, void *user_p)
{
FILE *fp = (FILE *)user_p;
size_t return_size = fwrite(buffer, size, nmemb, fp);
return return_size;
}
static size_t head_process_data(char *buffer, size_t size, size_t nitems, void *userdata)
{
char *head_line = userdata;
printf("nitems = %d\n", nitems);
strncpy(head_line, (const char *)buffer, nitems);
*(head_line + nitems) = 0;
printf("head info : %s", head_line);
return nitems;
}
static void baidu_get_test(void)
{
/*
* 获取一个easy句柄,后面通过这个句柄进行通信
*/
CURL *easy_handle = curl_easy_init();
if(!easy_handle) {
printf("curl_easy_init Err \n");
curl_global_cleanup();
return ;
}
/*
* 打开一个data.html文件,用于存储百度返回的数据
*/
FILE *fp = fopen("data.html", "w+");
char *head_line = (char *)malloc(100*1024);
/*
* 设置libcurl的选项,没有指定http访问方法,libcurl默认使用get方法
*/
curl_easy_setopt(easy_handle, CURLOPT_URL, "http://www.baidu.com");
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, baidu_get_test_cb);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, fp);
/*
* 增加调试功能,可以查看libcurl的执行过程
*/
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE, 1);
/*
* 接收http头信息
*/
curl_easy_setopt(easy_handle, CURLOPT_HEADERFUNCTION, head_process_data);
curl_easy_setopt(easy_handle, CURLOPT_HEADERDATA, head_line);
/*
* 执行访问
*/
CURLcode code = curl_easy_perform(easy_handle);
if(CURLE_OK != code) {
printf("curl_easy_perform %d\n", code);
}
free(head_line);
fclose(fp);
/*
* 最后记得释放句柄
*/
curl_easy_cleanup(easy_handle);
}
static void print_version_info(void)
{
curl_version_info_data *version_info = curl_version_info(CURLVERSION_NOW);
printf("version:%s\n", version_info->version);
printf("host:%s\n", version_info->host);
printf("ssl_version:%s\n", version_info->ssl_version);
}