网络编程知识预备(5) ——libcurl库安装及其编程访问百度首页

本文为学习笔记,整合课程内容以及下列文章:

其中,libcurl函数库常用字段解读部分:

参考博文:原文地址
作者:冬冬他哥哥

目录

  • Libcurl库简介
  • Libcurl等三方库的通用编译方法
    • 三方库使用前通读方法
    • 库的配置、编译、安装
  • 调用libcurl编程访问百度主页
    • 代码
    • 编译注意(编译时链接库、头文件路径,运行需添加动态库为环境变量)
  • libcurl函数库常用字段解读
    • 1.curl_global_init():初始化libcurl
    • 2.curl_easy_init():拿到句柄
    • 3.curl_easy_setopt(CURL *handle, CURLoption option, parameter):设置传输选项</h3>
    • 4.curl_easy_perform():执行任务</h3>
    • 5.curl_easy_cleanup():释放内存</h3>
  • 往期文章

Libcurl库简介

在linux下用c语言做HTTP的编程有一种方法是依赖于这个libcurl库,以后做跨平台网络协议相关的开发,第一个要想到的就是它。

libcurl是一个跨平台的网络协议库,支持http, https, ftp等协议,libcurl同样支持:

(1)HTTPS证书授权
(2)HTTP POST, HTTP PUT, FTP 上传
(3) HTTP基本表单上传,代理,cookies,和用户认证

库下载地址:库下载

在这里插入图片描述

然后发送到linux开发环境中。

Libcurl等三方库的通用编译方法

三方库使用前通读方法

解压下载的库

tar xvf curl-7.71.1.tar.bz2

进入文件夹

cd curl-7.71.1

对于这种开源的包,一定要学会它的使用:

先看README:

vi README

并没有发现一些特别有用的东西。

在这里插入图片描述


没关系,去看这个

docs文件夹很重要,一般是对README的补充

cd docs

不需要看太多,看类似于这个:前面README提到的相关的API手册

vi curl.1

也很难受,真提取不到什么信息。

嵌入式开发变得简单了是因为嵌入式经过十几二十年的发展有很多人对其进行解读,写了很多文章。

重点是看INSTALL文件

还是重点来看看docs下的INSTALL文件,库一定要学会安装才能使用。

在这里插入图片描述


卧槽,外国人在绕圈圈,大概看看INSTALL.md

在这里插入图片描述

可以看到./configure后面没有跟任何参数就是默认安装位置了,这里我们肯定要做配置,不配置都不知道文件安装到哪里去了

make就是编译的意思
make install就是把编译的结果拷贝到根的指定文件夹底下

关于帮助:
在这里插入图片描述不在原本默认的路径下安装说明:
在这里插入图片描述
配置是否支持https:
在这里插入图片描述
回到/curl-7.71.1目录下,configure --help看看

./configure --help

[注意]help前不用加空格,我加了反而显示不了帮助信息了。

可以看到上文所提及的安装路径配置:
在这里插入图片描述
也可以看到特别重要的交叉编译说明:
在这里插入图片描述

库的配置、编译、安装

(1)安装位置的更改:

配置为:$获取当前路径,编译的时候会自动生成_install文件夹,并且把编译生成的东西全部放入这个文件夹。

./configure --prefix=$PWD/_install

另外,这是针对于交叉编译的配置:编译后在树莓派上用
./configure --prefix=$PWD/_install --host=arm-linux
这样,在ubuntu中就会使用arm-gcc进行编译

如果上述操作直接在树莓派上进行,则不用再去额外配置交叉编译。工作中开发板往往没有编译工具,需要在上位机上进行编译,那么这里就要进行交叉编译配置。

(2)开始编译

make

(3)安装

make install

(4)预览

进入 /_install

我们用的是头文件

cd include

进入里面的这个

cd curl

这些都是要用到的头文件
在这里插入图片描述就像树莓派编译是要链接库一样

gcc a.c -lwiringPi -lpthread

用到这个库的时候,我们同样需要链接_install/lib里面的libcurl.so动态库 (.a是静态库)

头文件主要是宏定义、声明一些函数等,具体函数实现在动态库里面。

调用libcurl编程访问百度主页

_install里的内容结合一下示例代码来访问一下百度。

代码

#include <stdio.h>
#include <curl/curl.h>typedef unsigned int bool;//数据类型别名用typedef  有分号
#define true 1            //宏定义(替换)用define         无冒号
#define false 0bool 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 ");   // 指定urlcurl_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");
}

为什么要有最开始的那三句代码呢?
类似于bool,true,faluse,这是C99标准才会支持,C++里有专门的bool类型,用来表示真或假。但是在C语言里没有这样的类型,为了修改方便直接这样替换。

编译注意(编译时链接库、头文件路径,运行需添加动态库为环境变量)

链接库和头文件再编译,同时注意指明他们的路径

gcc getAndPost.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl

注意:动态库静态库的链接用-L,而头文件用-I

错误排查:

(1)提示找不到头文件#include <curl/curl.h>,说明没有指明头文件的路径

(2)如果只是使用-L是默认去usr/lib下去找的,会提示找不到库文件的路径cannot find -lcurl

(3)如果编译报错一堆函数不认识,函数是存在库里面的,说明没有链接库

usr/bin/ld: getAndPost.c:(.text+0x1a2): undefined reference to `curl_easy_init'
/usr/bin/ld: getAndPost.c:(.text+0x1d2): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x1f6): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x217): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x238): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x244): undefined reference to `curl_easy_perform'

可以看到已经生成了可执行文件./a.out

直接运行这个./a.out是会报错的(为什么我没有报错??可能是我用的Ubuntu20,老师是18.04??不,很有可能是因为我当时网络是断开的)

error while loading shared libraries: libcurl.so.4:cannot open shared object file:no such file or directory

原因是运行时要链接动态库,没有添加环境变量,忘记怎么添加咋办?面向百度,export lib path

export LD_LIBRARY_PATH=./curl-7.71.1/_install/lib/

成功运行后,可以看到vi /tmp/get.html中已经有了百度官网的代码。(仅贴出部分)

在这里插入图片描述


这跟我们平常去访问百度是一样的,只是用了前端css去排版的比较好看罢了,当你右键查看页面源码就知道了。

vi /tmp/port.html里面不会有东西,因为访问失败了:新浪的用户和密码不匹配。

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系列的函数中。

后续所有的操作都是对这个指针进行设置,把这种类型的指针就叫做句柄,实例:

在这里插入图片描述

其实socket服务器再socket函数后生成的fd,后续的bind,accept等操作也是基于这个fd,也可以理解为句柄

3.curl_easy_setopt(CURL *handle, CURLoption option, parameter):设置传输选项

参数:1)CURL类型的指针
(2)CURLoption类型的选项.(都在curl.h库里有定义,man 也可以查看到)3)parameter 既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量,取决于第二个参数。

根据设置的传输选项,实现回调函数以完成用户特定任务(设置与操作句柄)

这个函数很重要,几乎所有的curl 程序都要频繁的使用它。它告诉curl库,程序将有如何的行为,比如要查看一个网页的html代码等。(这个函数有些像ioctl函数)

第二个参数CURLoption常用的宏:

  • (1)CURLOPT_URL: 设置访问URL,就是设置访问的网址
  • (2)CURLOPT_POSTFIELDS

post请求中:以&拼接字符串的形式把参数链接起来,下篇文章提到的翔云人工智能平台OCRkey和密码就要放在这里传输。

curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86");    // 指定post内容:用户信息,尝试登陆新浪邮箱
  • (3)CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA

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);//请求回来的所有数据都放到文件中

4.curl_easy_perform():执行任务

在初始化CURL类型的指针 以及curl_easy_setopt完成后调用. 就像字面的意思所说perform就像是个舞台.让我们设置的option 运作起来。

5.curl_easy_cleanup():释放内存

结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。

该死的a库不好用

./a.out: /usr/lib/arm-linux-gnueabihf/libssl.so.1.1: version `OPENSSL_1_1_1' not found (required by ./curl-7.71.1/_install/lib/libcurl.so.4)

往期文章

网络编程知识预备(1) ——了解OSI网络模型
网络编程知识预备(2) ——浅显易懂的三次握手与四次挥手
网络编程知识预备(3) ——SOCKET、TCP、HTTP之间的区别与联系
网络编程知识预备(4) ——了解HTTP协议与HTTPS协议
网络编程知识预备(5) ——libcurl库安装及其编程访问百度首页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JSP(Servlet)中从连接池获取连接

1) 建立连接。 2) 执行SQL。 3) 处理结果。 4) 释放资源。 Connection pool&#xff1a;连接池 DataSource&#xff1a; LDAP ( Light directory access protocal )轻量级目录访问协议。 JNDI ( java naming director interface ) Java 命名目录接口。 使用连接池&#xff1a; …

文件系统模拟程序python_如何使用sh实现Python虚拟文件系统

我已经建立了一个模拟操作系统的Python脚本。它有一个命令提示符和一个虚拟文件系统。我使用shelve模块来模拟文件系统&#xff0c;它是多维的&#xff0c;以便支持目录的层次结构。但是&#xff0c;我在执行“cd”命令时遇到问题。我不知道如何进出目录&#xff0c;即使我有一…

udhcpd配置及使用

udhcpd配置及使用 1. 修改/etc/udhcpd.conf 修改 interface ra0 #default: eth0 为对应网卡 解决error, Unable to open /var/lib/misc/udhcpd.leases for reading&#xff0c; 在板子上执行以下命令&#xff1a; # mkdir -p /var/lib/misc/ # touch /var/lib/misc/udhcp…

智能家居 (9) ——人脸识别摄像头安装实现监控功能

目录摄像头模块安装安装mjpg-streamer库开启监控功能往期文章摄像头模块安装 注意&#xff1a;安装要下电安装&#xff0c;不能带电&#xff01;连接其他硬件模块的时候也是。 安装mjpg-streamer库 树莓派利用pi Camera模块&#xff0c;通过mjpg-streamer软件获取视频&#xf…

清理localstorage_vue 界面刷新数据被清除 localStorage的使用详解

localStorage是html5新增的一个本地存储API,它有5M的大小空间,通过(key,value)的方式存储在浏览器中window.localStorage.setItem(key, value); //储存文件window.localStorage.getItem(key); //读取文件window.localStorage.removeItem(key); //清除文件vue中使用方法&#xf…

洛谷p2234/BZOJ1588 [HNOI2002]营业额统计

题目链接&#xff1a;洛谷BZOJ 分析&#xff1a; 好像没有什么好说的就是一个平衡树的板子……唯一要注意的就是这里要找的并不是严格的前驱和后继&#xff0c;因为如果找到之前某一天的营业额和它相等那么差就是0&#xff0c;所以我们仍然在结构体中开一个域cnt来存储同一个元…

WSDL中文版——详解

为什么使用WSDL? 像Internet协议之类的标准有没有为权威所利用&#xff0c;或者人们这样看待它是因为顺之所获的好处远远超出了代价&#xff1f;曾经有许多试图建立的标准都流产了。有时候&#xff0c;那些还没有普遍使用的标准甚至由法令或政府规定强行推出&#xff1a;Ada语…

设备树和pinctrl粗解

上次文章中 我以DS18b20为例&#xff0c;在设备树中定义了ds18b20的资源&#xff08;device&#xff09;&#xff0c;当时是依葫芦画瓢&#xff0c;没有深入探究&#xff0c;本文主要探讨下pin在设备树中的描述 参考文章&#xff1a;Linux内核中的GPIO系统之&#xff08;3&…

八大排序算法(C语言实现)

摘自&#xff1a;八大排序算法&#xff08;C语言实现&#xff09; 作者&#xff1a;2021dragon 发布时间&#xff1a; 2021-05-16 10:46:37 网址&#xff1a;https://blog.csdn.net/chenlong_cxy/article/details/116563972 目录 直接插入排序希尔排序选择排序堆排序冒泡排序快…

python qq签到_Yii Framework 中文网每天签到 Python 脚本

Yii 春节前的重磅新闻&#xff1a;Yii 2.0.16 版本发布了经过国内 Yii 使用者坚持不懈的进行国际化翻译&#xff0c;以及在中国进行大量的宣传和推广&#xff0c;Yii China 目前已经成为全球最大的 Yii 中文社区也就是 Yii Framework 中文网&#xff0c;地址为 www.yiichina.co…

codeforces 1060 A

https://codeforces.com/contest/1060/problem/A 题意&#xff1a;电话号码是以8开头的11位数&#xff0c;给你n 个数问最多可以有多少个电话号码 题解&#xff1a;min&#xff08;8的个数&#xff0c;n/11&#xff09; 代码如下&#xff1a; #include <map> #include &l…

嵌入式linux 自动获取IP 及 自动校时

最近要调用百度人脸识别API做个东西&#xff0c;发现百度API在桌面端QT程序跑的贼溜&#xff0c;可以到了嵌入式板子上发现就post没了返回信息。 一、嵌入式端udhcpc自动获取IP 1.在开发板建立文件夹#mkdir /usr/share/udhcpc/ -p 2.先拷贝busybox 源码目录下的 busybox-1.27…

MYSQL MVCC实现及其机制

多版本并发控制 Multiversion Concurrency Control 大部分的MySQL的存储 引擎&#xff0c;比如InnoDB&#xff0c;Falcon&#xff0c;以及PBXT并不是简简单单的使用行锁机制。它们都使用了行锁结合一种提高并发的技术&#xff0c;被称为MVCC&#xff08;多版本并 发控制&#x…

树莓派外设开发之控制继电器(组)

目录控制继电器控制继电器组控制继电器 选择7号引脚作为继电器信号输出控制端。 代码&#xff1a; #include <wiringPi.h> #include <stdio.h> #define SWITCHER 7 // 7为树莓派物理引脚编码和wiringPi编码。在树莓派功能名为GPIO.7int main() {int cmd;if( wiri…

piovt table python_python – Pandas:pivot和pivot_table之间的区别...

我有以下数据帧.df.head(30)struct_id resNum score_type_name score_value0 4294967297 1 omega 0.0648401 4294967297 1 fa_dun 2.1856182 4294967297 1 fa_dun_dev 0.0000273 4294967297 1 fa_dun_semi 2.1855914 4294967297 1 ref -1.1911805 4294967297 2 rama -0.7951616…

读《系统虚拟化-原理与实现》-第一章

一、虚拟化的实现: 在系统中加入一个虚拟化层&#xff0c;虚拟化层将下层资源抽象成另一形式的资源&#xff0c;提供给上层使用 1. 是虚拟化迁移的基础 2. 提高了移植性 二、几种虚拟化 1.硬件抽象层上的虚拟化 通过虚拟硬件抽象层来实现虚拟机 2.操作系统层上的虚拟化 操…

怎样查看电脑开机记录

在Windows XP中&#xff0c;我们可以通过“事件查看器”的事件日志服务查看计算机的开、关机时间。因为事件日志服务会随计算机一起启动和关闭&#xff0c;并在事件日志中留下记录。 在这里有必要介绍两个ID号&#xff1a;6006和6005。在事件查看器里ID号为6006的事件表示事件日…

[BZOJ2725/Violet 6]故乡的梦

Description Input Output Sample Input 6 7 1 2 1 2 3 1 3 4 2 4 5 1 5 6 1 1 3 3 4 6 3 1 6 4 1 2 1 3 4 3 6 5 Sample Output 7 6 Infinity 7 HINT 其实这题和[TJOI2012]桥基本差不多&#xff0c;如果不是最短路径上的边&#xff0c;那直接输出最短路即可。否则就按照[TJOI2…

智能家居 (3) ——智能家居工厂模式介绍实现继电器控制灯

目录智能家居工厂模式整体设计框架继电器控制灯代码contrlEquipments.h 文件&#xff08;设备类&#xff09;mainPro.c 文件&#xff08;主函数&#xff09;bathroomLight.c 文件&#xff08;浴室灯&#xff09;secondfloorLight.c 文件&#xff08;二楼灯&#xff09;livingro…

机器人离线编程画圆误差解决方案_工业机器人离线编程-误差分析和解决方案...

编&#xff1a;张山发&#xff1a;03/03/2019按&#xff1a;为便于更多读者朋友了解工业机器人离线编程/仿真&#xff0c;本文中尽量规避专业名词和深入的专业讲解。——————————————————————————————————国内工业机器人应用领域越来越广&…