• 智能家居——libcurl库简介


    科普:

    • 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
    
    • 1

    进入文件夹

    cd curl-7.71.1
    
    • 1

    (1)三方库使用前通读方法

    关于第三方库的使用手册可以阅读README文件,或者进入docs目录下阅读INSTALL.md文件

    (2)库的配置、编译、安装

    阅读INSTALL.md文件可知在unix环境下的安装步骤和安装时候指定的配置

    在这里插入图片描述
    安装步骤:

    在这里插入图片描述

    配置参数查看:

    ./configure --help
    
    • 1

    通过配置更改安装位置:

    在这里插入图片描述

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

    ./configure --prefix=$PWD/_install
    
    • 1

    通过配置完成交叉编译:

    在这里插入图片描述
    代码案例:编译后在树莓派上用,此处用的是树莓派的交叉编译工具链而不是gcc(树莓派没有cmake则需要在宿主机上进行交叉编译)

    ./configure --prefix=$PWD/_install --host=arm-linux
    
    • 1

    编译、安装

    make
    make install //将编译后的文件拷贝到根目录的指定文件夹下
    
    • 1
    • 2

    安装完成后在的当前路径下会有_install文件夹

    此时头文件在/include/curl下
    在这里插入图片描述
    链接库的位置在/lib
    在这里插入图片描述

    三、测试代码

    功能:调用libcurl编程访问百度主页
    注意: C++里有专门的bool类型,用来表示真或假。但是在C语言里没有这样的类型,为了修改方便直接选择替换bool数据类型以及true和false变量( 类似于bool,true,faluse,这是C99标准才会支持)
    测试代码来源:http协议之libcurl

    (1)代码:

    #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");
    }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    (2)编译和运行

    gcc demo1.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl
    
    • 1

    注意:

    • 编译时链接库、头文件路径、库的名称
    • 若运行的时候报错
      在这里插入图片描述 运行需添加动态库为环境变量(不报错则不需要,可能因为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         //没有额外的初始化。
    
    • 1
    • 2
    • 3
    • 4

    (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型的变量,取决于第二个参数。
    
    • 1
    • 2
    • 3

    第二个参数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句柄
  • 相关阅读:
    翻译Excel文档名不求人:详细指南
    Ablebits Ultimate Suite for Excel
    文本分析:NLP 魔法!
    练习31-35:多表关联查询、多条件自连接查询、子查询、窗口函数等
    如何在Mac上停止旋转等待光标?这里提供详细步骤
    java毕业设计外卖管理系统mybatis+源码+调试部署+系统+数据库+lw
    数据库安全策略与实施措施
    【Jetpack】Room 预填充数据 ( 安装 DB Browser for SQLite 工具 | 创建数据库文件 | 应用中设预填充数据对应的数据库文件 | 预填充数据库表字段属性必须一致 )
    HyperBDR新版本上线,自动化容灾兼容再升级!
    周少剑,很少见
  • 原文地址:https://blog.csdn.net/NRWHF/article/details/127953130