文章目录
科普:
- cURL是一个利用URL语法在命令行下工作的文件传输工具,1997年首次发行。它支持文件上传和下载,所以是综合传输工具,但按传统,习惯称cURL为下载工具。cURL还包含了用于程序开发的libcurl。
- cURL支持的通信协议有FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3、SMTP和RTSP。
- curl还支持SSL认证、HTTP POST、HTTP PUT、FTP上传, HTTP form based upload、proxies、HTTP/2、cookies、用户名+密码认证(Basic, Plain, Digest, CRAM-MD5, NTLM, Negotiate and Kerberos)、file transfer resume、proxy tunneling。
一、Libcurl库简介
- libcurl库:在linux下用c语言做HTTP的编程,可以用于做跨平台网络协议相关的开发
- libcurl是一个跨平台的网络协议库,支持http, https, ftp等协议,libcurl同样支持:
(1)HTTPS证书授权
(2)HTTP POST, HTTP PUT, FTP 上传
(3)HTTP基本表单上传,代理,cookies,和用户认证
libcur库下载地址:下载curl-7.71.1.tar.bz2
将下载好的压缩包发送到ubuntu
二、Libcurl等三方库的通用编译方法
解压下载的库
tar xvf curl-7.71.1.tar.bz2
进入文件夹
cd curl-7.71.1
(1)三方库使用前通读方法
关于第三方库的使用手册可以阅读README
文件,或者进入docs目录下阅读INSTALL.md
文件
(2)库的配置、编译、安装
阅读INSTALL.md文件可知在unix环境下的安装步骤和安装时候指定的配置
安装步骤:
配置参数查看:
./configure --help
通过配置更改安装位置:
代码案例:$ 获取当前路径,编译的时候会自动生成_install文件夹,并且把编译生成的东西全部放入这个文件夹。
./configure --prefix=$PWD/_install
通过配置完成交叉编译:
代码案例:编译后在树莓派上用,此处用的是树莓派的交叉编译工具链而不是gcc(树莓派没有cmake则需要在宿主机上进行交叉编译)
./configure --prefix=$PWD/_install --host=arm-linux
编译、安装
make
make install //将编译后的文件拷贝到根目录的指定文件夹下
安装完成后在的当前路径下会有_install文件夹
此时头文件在/include/curl下
链接库的位置在/lib
三、测试代码
功能:调用libcurl编程访问百度主页
注意: C++里有专门的bool类型,用来表示真或假。但是在C语言里没有这样的类型,为了修改方便直接选择替换bool数据类型以及true和false变量( 类似于bool,true,faluse,这是C99标准才会支持)
测试代码来源:http协议之libcurl
(1)代码:
#include <stdio.h>
#include <curl/curl.h>
typedef unsigned int bool;//数据类型别名用typedef 有分号
#define true 1 //宏定义(替换)用define 无冒号
#define false 0
bool getUrl(char *filename)//GET请求
{
CURL *curl;
CURLcode res;
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL) // 返回结果用文件存储
return false;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: Agent-007");
curl = curl_easy_init(); // 初始化
if (curl)
{
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");// 代理
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); //将返回的http头输出到fp>指向的文件,
//即为filename文件,而主函数传入的参数是 /tmp/get.html,即为真正保存在get.html文件中
curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp); //将返回的html主体数据输出到fp指向的文件
res = curl_easy_perform(curl); // 执行
if (res != 0) {
curl_slist_free_all(headers); //释放句柄
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
}
bool postUrl(char *filename)//POST请求
{
CURL *curl;
CURLcode res;
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL)
return false;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt"); // 指定cookie文件
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86"); // 指定post内容:用户信息 字段之间&连接,尝试登陆新浪邮箱
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");
curl_easy_setopt(curl, CURLOPT_URL, " http://mail.sina.com.cn/cgi-bin/login.cgi "); // 指定url
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);//执行
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
int main(void)
{
getUrl("/tmp/get.html");
postUrl("/tmp/post.html");
}
(2)编译和运行
gcc demo1.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl
注意:
- 编译时链接库、头文件路径、库的名称
- 若运行的时候报错
运行需添加动态库为环境变量(不报错则不需要,可能因为ubuntu版本不一样)export LD_LIBRARY_PATH=./curl-7.71.1/_install/lib/
export | grep LD_LIB
可以看到添加的路径- 需要添加环境变量的原因可能是库之间的依赖问题
(3)查看获取网页源代码
- 成功运行后,可以看到
vi /tmp/get.html
中已经有了百度官网的代码。 而 vi /tmp/port.html 里面不会有东西,因为账号密码没有填写正确
四、libcurl函数库常用字段解读
参考博文:http协议之libcurl
(1)curl_global_init():初始化libcurl
-
函数只能用一次。(其实在调用curl_global_cleanup 函数后仍然可再用)
-
如果这个函数在curl_easy_init函数调用时还没调用,它将由libcurl库自动调用,所以多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用。
-
注意:虽然libcurl是线程安全的,但curl_global_init是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。
参数:flags
CURL_GLOBAL_ALL //初始化所有的可能的调用。(最常用)
CURL_GLOBAL_SSL //初始化支持 安全套接字层。
CURL_GLOBAL_WIN32 //初始化win32套接字库。
CURL_GLOBAL_NOTHING //没有额外的初始化。
(2)curl_easy_init():拿到句柄
-
用来初始化一个CURL的指针(有些像返回FILE类型的指针一样)。相应的在调用结束时要用curl_easy_cleanup函数清理。
-
一般curl_easy_init意味着一个会话的开始. 它会返回一个easy_handle(CURL*对象), 一般都用在easy系列的函数中。
-
后续所有的操作都是对这个指针进行设置,把这种类型的指针就叫做句柄
(3)curl_easy_setopt(CURL *handle, CURLoption option, parameter):设置传输选项
- 这个函数很重要,几乎所有的curl 程序都要频繁的使用它。它告诉curl库,程序将有如何的行为,比如要查看一个网页的html代码等。(这个函数有些像ioctl函数)
- 根据设置的传输选项,实现回调函数以完成用户特定任务(设置与操作句柄)
参数:
(1)CURL类型的指针
(2)CURLoption类型的选项.(都在curl.h库里有定义,man 也可以查看到)
(3)parameter 既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量,取决于第二个参数。
第二个参数CURLoption常用的宏:
-
(1)CURLOPT_URL:
- 设置访问URL(访问的网址)
-
(2)CURLOPT_POSTFIELDS
- 在post请求中:以 & 拼接字符串的形式把参数链接起来
- 例如:
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86");
-
(3)CURLOPT_WRITEFUNCTION
- 回调函数:网页有数据请求回来的时候,如何去处理这些数据。函数多做数据保存的功能,如处理下载文件。
- 设置的回调函数格式要求为:
size_t function( void *ptr, size_t size, size_t nmemb, void *stream);
- 第一个参数:无类型指针(看做字符串)指向的就是数据,可以用函数
strncpy或strcpy
接收到本地 - 第二个参数:回调函数的名称
- 第一个参数:无类型指针(看做字符串)指向的就是数据,可以用函数
-
(4)CURLOPT_WRITEDATA
- CURLOPT_WRITEDATA 用于表明CURLOPT_WRITEFUNCTION函数中的stream指针的来源。
- libcurl会提供一个默认的回调函数,它只是简单的将接收到的数据打印到标准输出
- 可以通过 CURLOPT_WRITEDATA 属性给默认回调函数传递一个已经打开的文件指针,用于将数据输出到文件里。
- 前提是已经打开一个文件流:
fp = fopen(filename, "w")
- 第三个参数传递文件指针,表示请求回来的所有数据都放到文件
- 前提是已经打开一个文件流:
(4)curl_easy_perform():执行任务
- 在初始化CURL类型的指针以及curl_easy_setopt完成后调用.,就像字面的意思所说 perform 就像是个舞台,让我们设置的option 运作起来。
(5)curl_easy_cleanup():释放内存
- 结束libcurl使用的时候,用来对 curl_global_init 做的工作清理。类似于close的函数。
- 参数是curl句柄