参考:网络编程知识预备(5) ——libcurl库简介及其编程访问百度首页_行稳方能走远的博客-CSDN博客
Http协议之libcurl实现 - 谢呈勖 - 博客园 (cnblogs.com)
目录
一、Libcurl库简介
二、Libcurl等三方库的通用编译方法
库的配置、编译、安装
(1)安装位置的更改:
(2)编译、安装
预览
三、调用libcurl编程访问百度主页
demo1.c
编译(编译时链接库、头文件路径)
运行(运行需添加动态库为环境变量)
四、libcurl函数库常用字段解读
1、curl_global_init():初始化libcurl
参数:flags
2、curl_easy_init():得到easy interface型指针,拿到句柄
3、curl_easy_setopt(CURL *handle, CURLoption option, parameter):设置传输选项
* 第二个参数CURLoption常用的宏
4.curl_easy_perform():执行任务
5.curl_easy_cleanup():释放内存
在linux下用c语言做HTTP的编程有一种方法是依赖于这个libcurl库,以后做跨平台网络协议相关的开发,第一个要想到的就是它。
libcurl是一个跨平台的网络协议库,支持http, https, ftp等协议,libcurl同样支持:
(1)HTTPS证书授权
(2)HTTP POST, HTTP PUT, FTP 上传
(3)HTTP基本表单上传,代理,cookies,和用户认证
库下载地址: Release 7.71.1 · curl/curl · GitHub
然后发送到linux开发环境中。
解压下载的库
tar xvf curl-7.71.1.tar.bz2
进入文件夹
cd curl-7.71.1
对于这种开源的包,一定要学会它的使用:
先看 README,docs 文件夹里的 curl.1 和INSTALL文件
回到/curl-7.71.1
目录下,configure --help看看
./configure --help
配置为:$ 获取当前路径,编译的时候会自动生成_install文件夹,并且把编译生成的东西全部放入这个文件夹。
./configure --prefix=$PWD/_install
./configure --prefix=$PWD/_install --host=arm-linux
make
make install
这些都是要用到的头文件
编译是要链接库一样
gcc a.c -lwiringPi -lpthread
用到这个库的时候,我们同样需要链接_install/lib
里面的libcurl.so
动态库 (.a
是静态库)‘
把_install
里的内容结合一下示例代码来访问一下百度。
#include
#include
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");
}
typedef unsigned int bool;//数据类型别名用typedef 有分号 #define true 1 //宏定义(替换)用define 无冒号 #define false 0
类似于
bool,true,faluse
,这是C99标准才会支持,C++里有专门的bool类型,用来表示真或假。但是在C语言里没有这样的类型,为了修改方便直接这样替换
gcc demo1.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl
注意:动态库静态库的链接用
-L
,而头文件用-I
生成了可执行文件./a.out
直接运行可能会报错(我没有报错,
可能是我用的Ubuntu20.04)。
原因是运行时要链接动态库,没有添加环境变量
export LD_LIBRARY_PATH=./curl-7.71.1/_install/lib/
成功运行后,可以看到 vi /tmp/get.html
中已经有了百度官网的代码。
而 vi /tmp/port.html
里面不会有东西,因为访问失败了:新浪的用户和密码不匹配。
Http协议之libcurl实现 - 谢呈勖 - 博客园 (cnblogs.com)
curl_global_init()
:初始化libcurl函数只能用一次。(其实在调用curl_global_cleanup 函数后仍然可再用)
如果这个函数在curl_easy_init
函数调用时还没调用,它将由libcurl库自动调用,所以多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用。
注意:虽然libcurl是线程安全的,但curl_global_init是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。
CURL_GLOBAL_ALL //初始化所有的可能的调用。(最常用)
CURL_GLOBAL_SSL //初始化支持 安全套接字层。
CURL_GLOBAL_WIN32 //初始化win32套接字库。
CURL_GLOBAL_NOTHING //没有额外的初始化。
curl_easy_init()
:得到easy interface型指针,拿到句柄用来初始化一个 curl 的指针(有些像返回FILE类型的指针一样)。相应的在调用结束时要用 curl_easy_cleanup 函数清理。
一般 curl_easy_init 意味着一个会话的开始. 它会返回一个 easy_handle (CURL*对象) , 一般都用在easy系列的函数中。
后续所有的操作都是对这个指针进行设置,把这种类型的指针就叫做句柄,实例:
其实socket服务器再socket函数后生成的fd,后续的bind,accept等操作也是基于这个fd,也可以理解为句柄
curl_easy_setopt(CURL *handle, CURLoption option, parameter)
:设置传输选项参数:
(1)CURL类型的指针
(2)CURLoption类型的选项.(都在curl.h库里有定义,man 也可以查看到)
(3)parameter 既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量,取决于第二个参数。
根据设置的传输选项,实现回调函数以完成用户特定任务(设置与操作句柄)
这个函数很重要,几乎所有的curl 程序都要频繁的使用它。它告诉curl库,程序将有如何的行为,比如要查看一个网页的html代码等。(这个函数有些像ioctl函数)
在post请求中:以 & 拼接字符串的形式把参数链接起来,下篇文章提到的翔云人工智能平台OCRkey和密码就要放在这里传输。
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86"); // 指定post内容:用户信息,尝试登陆新浪邮箱
CURLOPT_WRITEFUNCTION使用举例
回调函数:网页有数据请求回来的时候,如何去处理这些数据。(做人脸识别,肯定要获得人脸识别的结果)
设置的回调函数格式要求为:
size_t function( void *ptr, size_t size, size_t nmemb, void *stream);
函数将在libcurl接收到数据后被调用,因此函数多做数据保存的功能,如处理下载文件。
①陈老师的车牌识别车牌识别
int BufferWriterFunc(char* data,size_t size,size_t nmemb,char *buffer)
{
strcpy(bufferData,data);//把返回的data数据放在本地的bufferData数组中
return size*nmemb;
}
//配置如下:
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,BufferWriterFunc);
②修改上面访问百度的代码
size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
{
char buf[1024] = {'\0'};
strncpy(buf,ptr,1024);
printf("===========get data ===========\n");
printf("%s\n",buf);
}
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,readData);
CURLOPT_WRITEDATA使用举例
也可以通过 CURLOPT_WRITEDATA 属性给默认回调函数传递一个已经打开的文件指针,用于将数据输出到文件里。
正如上面访问百度的例子:
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL)//提前打开了一个文件流
return false;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);//请求回来的所有数据都放到文件中
在初始化CURL类型的指针 以及curl_easy_setopt完成后调用. 就像字面的意思所说 perform 就像是个舞台.让我们设置的option 运作起来。
结束libcurl使用的时候,用来对 curl_global_init 做的工作清理。类似于close的函数。
智能家居(1) —— 工厂模式引入&工厂模式实现继电器控制
智能家居(2) —— 工厂模式实现烟雾报警
智能家居(3) —— 串口通信(语音识别)线程控制
智能家居(4) —— 网络服务器线程控制
智能家居(5) —— 智能家居项目整合(语音控制线程,网络控制线程、烟雾报警线程)
网络编程知识预备(1) —— 7层OSI网络模型
网络编程知识预备(2) —— 三次握手与四次挥手、半连接状态、2MSL
网络编程知识预备(3) —— TCP流量控制(滑动窗口)、拥塞控制
网络编程知识预备(4) —— SOCKET、TCP、HTTP之间的区别与联系
网络编程知识预备(5) —— 了解应用层的HTTP协议与HTTPS协议
网络编程知识预备(6) —— libcurl库简介及其编程访问百度首页
智能家居(6) —— 香橙派摄像头安装实现监控功能
智能家居(7) —— 人脸识别 & 翔云平台编程使用(编译openSSL支持libcurl的https访问、安装SSL依赖库openSSL)
智能家居(8) —— 香橙派摄像头加入设备工厂