Linux下的http请求有许多种方式,其中curl库是C语言封装的一个强大的库,使用curl比封装socket更加方便。
Curl是一款著名的字符界面下的下载工具,支持HTTP、HTTPS、FTP、FTPS、DICT、TELNET、LDAP、FILE,和GOPHER。此外还具有cookies支持、断点续传、FTP上传、密码支持、SSL支持和代理支持等特性。curl同时还提供了一套libcurl的库,开发者可以基于这个库开发其他下载工具。
Curl 的官网下载地址:http://curl.haxx.se/download/
截止2018.4月更新至7.59.0版本。
1.下载并解压
下载到的压缩包为curl-7.59.0.tar.gz使用命令:
$wget http://curl.haxx.se/download/curl-7.59.0.tar.gz
解压:
$tar -zxvf curl-7.59.0.tar.gz
2.进入解压出的目录curl-7.59.0.
$cd curl-7.59.0
3.配置参数
sudo ./configure
4.编译
sudo make sudo make install
5.检查安装
使用 curl –version 检查是否更新成功,出现如下情况安装基本成功.
$curl --version
1.下载并解压
下载到的压缩包为curl-7.59.0.tar.gz使用命令:
$wget http://curl.haxx.se/download/curl-7.59.0.tar.gz
解压:
$tar -zxvf curl-7.59.0.tar.gz
2.进入解压出的目录curl-7.59.0.
$cd curl-7.59.0
3.建立编译夹
$mkdir install
4.配置参数
./configure --host=arm-fsl-linux-gnueabi prefix=`pwd`/install CC=arm-fsl-linux-gnueabi-gcc CXX=arm-fsl-linux-gnueabi-g++
【注意】
–host=arm-fsl-linux-gnueabi表示该软件编译完成后在arm平台上运行
–prefix后面为软件安装目录
5.编译
$make
$make install
6.查看
$ls install/
libcurl头文件在install/include/curl目录
# ls install/include/curl
$ls install/lib
8.测试
Test.c
#include
#include
#include
const char data[]="this is what we post to the silly web server";
struct WriteThis
{
const char *readptr;
long sizeleft;
};
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
struct WriteThis *pooh = (struct WriteThis *)userp;
if(size*nmemb < 1)
return 0;
if(pooh->sizeleft)
{
*(char *)ptr = pooh->readptr[0]; /* copy one single byte */
pooh->readptr++; /* advance pointer */
pooh->sizeleft--; /* less data left */
return 1; /* we return 1 byte at a time! */
}
return 0; /* no more data left to deliver */
}
int main(void)
{
CURL *curl;
CURLcode res;
struct WriteThis pooh;
pooh.readptr = data;
pooh.sizeleft = (long)strlen(data);
/* In windows, this will init the winsock stuff */
res = curl_global_init(CURL_GLOBAL_DEFAULT);
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "curl_global_init() failed: %s\n",
curl_easy_strerror(res));
return 1;
}
/* get a curl handle */
curl = curl_easy_init();
if(curl)
{
/* First set the URL that is about to receive our POST. */
curl_easy_setopt(curl, CURLOPT_URL, "http://47.106.72.113/");
/* Now specify we want to POST data */
curl_easy_setopt(curl, CURLOPT_POST, 1L);
/* we want to use our own read function */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* pointer to pass to our read function */
curl_easy_setopt(curl, CURLOPT_READDATA, &pooh);
/* get verbose debug output please */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/*
If you use POST to a HTTP 1.1 server, you can send data without knowing
the size before starting the POST if you use chunked encoding. You
enable this by adding a header like "Transfer-Encoding: chunked" with
CURLOPT_HTTPHEADER. With HTTP 1.0 or without chunked transfer, you must
specify the size in the request.
*/
#ifdef USE_CHUNKED
{
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
/* use curl_slist_free_all() after the *perform() call to free this
list again */
}
#else
/* Set the expected POST size. If you want to POST large amounts of data,
consider CURLOPT_POSTFIELDSIZE_LARGE */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, pooh.sizeleft);
#endif
#ifdef DISABLE_EXPECT
/*
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue"
header. You can disable this header with CURLOPT_HTTPHEADER as usual.
NOTE: if you want chunked transfer too, you need to combine these two
since you can only set one list of headers with CURLOPT_HTTPHEADER. */
/* A less good option would be to enforce HTTP 1.0, but that might also
have other implications. */
{
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Expect:");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
/* use curl_slist_free_all() after the *perform() call to free this
list again */
}
#endif
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
执行命令:
$arm-fsl-linux-gnueabi-gcc -I/home/farsight/curl-7.59.0/install/include -L/home/farsight/curl-7.59.0/install/lib -o test test.c -lcurl
将可执行文件test拷贝到开发板,执行程序。可以见到如下信息。
* Trying 47.106.72.113...
* TCP_NODELAY set
* Connected to 47.106.72.113 (47.106.72.113) port 80 (#0)
> POST / HTTP/1.1
Host: 47.106.72.113
Accept: */*
Content-Length: 44
Content-Type: application/x-www-form-urlencoded
* We are completely uploaded and fine
< HTTP/1.1 405 Not Allowed
< Server: nginx/1.8.1
< Date: Mon, 25 Jun 2018 05:45:38 GMT
< Content-Type: text/html
< Content-Length: 172
< Connection: keep-alive
<
<html>
<head><title>405 Not Allowedtitle>head>
<body bgcolor="white">
<center><h1>405 Not Allowedh1>center>
<hr><center>nginx/1.8.1center>
body>
html>
* Connection #0 to host 47.106.72.113 left intact
libcurl测试实例集:https://curl.haxx.se/libcurl/c/example.html
关于libcurl实例参看以上网址。
1.全局初始化
CURLcode curl_global_init(long flags);
flags:
CURL_GLOBAL_ALL //初始化所有内部的模块
CURL_GLOBAL_SSL //初始化支持安全套接字
CURL_GLOBAL_WIN32 //初始化win32套接字库
CURL_GLOBAL_NOTHING //不初始化任何额外模块
CURL_GLOBAL_DEFAULT //与CURL_GLOBAL_ALL相同
该函数必须再所有其他libcurl函数调用前被调用,从而构建整个libcurl函数运行所需的环境,多次调用是幂等的。flags参数能够使用”或”操作符进行多个选项的拼接。一般情况使用CURL_GLOBAL_ALL是最好的选择。
该函数不是线程安全的,不能在程序的其他线程中调用,只能应用程序开始时,进行全局初始化调用。虽然不调用这个函数,使用curl_easy_init也会自行调用该函数,但在多线程处理时,可能出现多次调用的情况,应避免。
2.创建当次请求句柄
每次请求都需要创建一个句柄,所有操作围绕以此句柄进行:
CURL *curl_handler = curl_easy_init();
3.设置属性
libcurl针对所有协议,统一使用一个简单的函数curl_easy_setopt进行设置,这大大简化了使用,不过需要参考不同协议设置不同的属性:
https://curl.haxx.se/libcurl/c/curl_easy_setopt.html
这里以http发送GET请求为例设置如下:
//设置请求的url
curl_easy_setopt(curl_handler, CURLOPT_URL, url);
//设置是否返回请求头
curl_easy_setopt(curl_handler, CURLOPT_HEADER, 1L);
//设置屏蔽其他信号
curl_easy_setopt(curl_handler, CURLOPT_NOSIGNAL, 1L);
//设置下载数据回调函数
curl_easy_setopt(curl_handler, CURLOPT_WRITEFUNCTION, write_func);
curl_easy_setopt(curl_handler, CURLOPT_WRITEDATA, write_data);
回调函数原型:
size_t function( void *ptr, size_t size, size_t nmemb, void *userp);
函数将在libcurl接收到数据后被调用。
void *ptr是下载回来的数据.
void *userp是用户指针, 用户通过这个指针传输自己的数据.
CURLOPT_WRITEDATA:设置回调函数中的void *userp指针的来源。
//设置是否使用下载进度控制函数
curl_easy_setopt(curl_handler, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl_handler, CURLOPT_PROGRESSFUNCTION, prog_func);
curl_easy_setopt(curl_handler, CURLOPT_PROGRESSDATA, pdata);
下载进度回调函数与下载数据的回调函数原型相同,data也相同。
//设置请求头
struct curl_list *header_list = NULL;
for (int i = 0; i < headers.size(); ++i) {
header_list = curl_slist_append(header_list, headers[i].c_str());
}
curl_easy_setopt(curl_handler, CURLOPT_HTTPHEADER, header_list);
curl_slist_free_all(header_list);
//其他选项
CURLOPT_HEADERFUNCTION
CURLOPT_HEADERDATA
只取HTTP头部数据, 处理与下载数据回调的处理相同.
CURLOPT_TIMEOUT
超时时间.
CURLOPT_CONNECTIONTIMEOUT
连接等待时间.
CURLOPT_FOLLOWLOCATION
设置支持302重定向
CURLOPT_RANGE
断点续传, 指定传输分片, 格式:”0-200”
其中,针对http协议,不同请求有特定的属性需要设置,下面依次列举:
- HEAD:需要设置CURLOPT_NOBODY为true
- DELETE:需要设置CURLOPT_CUSTOMREQUEST为”DELETE”
- PUT:需要设置CURLOPT_UPLOAD为true,同时设置CURLOPT_READFUNCTION、CURLOPT_READDATA、CURLOPT_INFILESIZE_LARGE
- POST:需要设置CURLOPT_POST为true,设置CURLOPT_POSTFIELDS、CURLOPT_POSTFIELDSIZE
4.执行
CURLcode curl_easy_perform(CURL *handler);
该函数执行当次请求创建的句柄,返回值有非常详细的定义libcurl库返回状态码解释与速查。
5.销毁当次请求句柄
void curl_easy_cleanup(CURL *handler);
该函数销毁当次请求创建的句柄。
6.全局析构
void curl_global_cleanup();
该函数销毁全局执行环境。
其他接口
libcurl除了上述常用接口外,提供了其他接口可以进行更为方便和精确的控制。
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... );
//支持的CURLINFO类型见此:https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html
curl_version() returns a pointer to the libcurl version string
curl_getdate() converts a date string to time_t
curl_formadd() build multipart form-data posts
curl_formfree() free a previously built form POST
curl_slist_append() builds a linked list
curl_slist_free_all() frees a whole curl_slist as made with curl_slist_append()
curl_easy_escape() URL encodes a string
curl_easy_unescape() URL decodes a string
libcurl官方教程:https://curl.haxx.se/libcurl/c/libcurl-tutorial.html