【libcurl库】OpenSSL 库、多线程、断点续传(二)

一、libcurl函数库常用字段解读

  • 1、curl_global_init():初始化libcurl
  • 2、curl_easy_init():得到easy interface型指针,拿到句柄
  • 3、curl_easy_setopt(CURL *handle, CURLoption option, parameter):设置传输选项
    • 第二个参数CURLoption option常用的宏:
    • CURLOPT_WRITEFUNCTION使用举例
    • CURLOPT_WRITEDATA使用举例
  • 4.curl_easy_perform():执行任务
  • 5.curl_easy_cleanup():释放内存

二、OpenSSL 库

  • 编译OpenSSL库支持libcurl的HTTPS访问

三、设置Http请求头

  • 自定义选项
  • 修改消息头
  • 删除消息头

四、获取http应答头信息
五、多线程问题
六、什么时候libcurl无法正常工作
七、关于密码
八、HTTP验证
九、代码示例

    1. 基本的http GET/POST操作
    1. 获取html网页
    1. 网页下载保存实例
    1. 进度条实例显示文件下载进度
    1. 断点续传实例

在这里插入图片描述
libcurl教程

一、libcurl函数库常用字段解读

libcurl函数库常用字段解读并设置数据读取回调函数

1、curl_global_init():初始化libcurl

CURLcode curl_global_init(long flags);函数只能用一次。(其实在调用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():得到easy interface型指针,拿到句柄

用来初始化一个 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):设置传输选项

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

参数

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

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

第二个参数CURLoption option常用的宏:

  • (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);

②修改上面访问百度的代码
在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>typedef unsigned int bool;//数据类型别名用typedef       有分号
#define true 1            //宏定义(替换)用define      无冒号
#define false 0size_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);
}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_WRITEFUNCTION, readData);//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");
}
gcc demo1.c -I /home/orangepi/curl-7.71.1/_install/include/ -L /home/orangepi/curl-7.71.1/_install/lib/ -lcurl
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的函数。

二、OpenSSL 库

交叉编译:OpenSSL_使wget支持https

背景:
交叉编译:wget

之前交叉编译出来的wget文件,在板子上运行时,不支持https解析。

需要在交叉编译wget时,加上openssl库文件。

交叉编译链中没有该库,所以需要自己交叉编译openssl。

配置文件:

wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz
tar -vxf openssl-1.1.1a.tar.gz
cd openssl-1.1.1a/
mkdir __install./config no-asm shared --prefix=$PWD/__install

修改Makefile文件:

#CROSS_COMPILE=
CROSS_COMPILE=aarch64-himix100-linux-#CNF_CFLAGS=-pthread -m64
CNF_CFLAGS=-pthread
#CNF_CXXFLAGS=-std=c++11 -pthread -m64
CNF_CXXFLAGS=-std=c++11 -pthread

保存退出,继续编译。

make
make install

编译OpenSSL库支持libcurl的HTTPS访问

在这里插入图片描述

vi docs/INSTALL.md
sudo ./configure --prefix=$PWD/_install --with-ssl
make
make install

使用 ./configure 配置参数的例子,通常用于配置和构建开源软件。这个命令的含义是配置软件以在当前目录下创建 _install 子目录,并使用指定的 SSL 库。

解释一下各个部分的含义:

  • ./configure: 这是一个配置脚本,用于检查系统环境并生成相应的 Makefile,以便后续执行 makemake install

  • --prefix=\$PWD/_install: 指定安装目录。$PWD 表示当前工作目录,_install 是一个子目录,指定安装到当前目录下的 _install 目录。

  • --with-ssl: 这个选项用于指定 SSL 库。它告诉配置脚本使用系统中安装的 SSL 库。在这里没有具体指定 SSL 库的路径,因为它会尝试在系统上查找已经安装的 SSL 库。

这个命令的目的是配置软件并将其安装到当前目录下的 _install 子目录中,同时使用系统中已经安装的 SSL 库。接下来,你可能会运行 make 来编译软件,然后运行 make install 将其安装到指定目录。

编译成功
在这里插入图片描述
在这里插入图片描述

三、设置Http请求头

 当使用libcurl发送http请求时,它会自动添加一些http头。我们可以通过CURLOPT_HTTPHEADER属性手动替换、添加或删除相应的HTTP消息头。

Hosthttp1.1(大部分http1.0)版本都要求客户端请求提供这个信息头。Pragma"no-cache"。表示不要缓冲数据。Accept"*/*"。表示允许接收任何类型的数据。Expect

 以POST的方式向HTTP服务器提交请求时,libcurl会设置该消息头为"100-continue",它要求服务器在正式处理该请求之前,返回一 个"OK"消息。如果POST的数据很小,libcurl可能不会设置该消息头。

自定义选项

 当前越来越多的协议都构建在HTTP协议之上(如:soap),这主要归功于HTTP的可靠性,以及被广泛使用的代理支持(可以穿透大部分防火墙)。 这些协议的使用方式与传统HTTP可能有很大的不同。对此,libcurl作了很好的支持。
 自定义请求方式(CustomRequest)
 HTTP支持GET, HEAD或者POST提交请求。可以设置CURLOPT_CUSTOMREQUEST来设置自定义的请求方式,libcurl默认以GET方式提交请求:

curl_easy_setopt(easy_handle, CURLOPT_CUSTOMREQUEST, "MYOWNREQUEST"); 

修改消息头

 HTTP协议提供了消息头,请求消息头用于告诉服务器如何处理请求;响应消息头则告诉浏览器如何处理接收到的数据。

struct curl_slist *headers=NULL; /* init to NULL is important */
headers = curl_slist_append(headers, "Hey-server-hey: how are you?");
headers = curl_slist_append(headers, "X-silly-content: yes");
/* pass our list of custom made headers */
curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers);
curl_easy_perform(easyhandle); /* transfer http */
curl_slist_free_all(headers); /* free the header list */

 对于已经存在的消息头,可以重新设置它的值:

headers = curl_slist_append(headers, "Accept: Agent-007"); 
headers = curl_slist_append(headers, "Host: munged.host.line"); 

删除消息头

 对于一个已经存在的消息头,设置它的内容为空,libcurl在发送请求时就不会同时提交该消息头:

headers = curl_slist_append(headers, "Accept:");

四、获取http应答头信息

 发出http请求后,服务器会返回应答头信息和应答数据,如果仅仅是打印应答头的所有内容,则直接可以通过curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, 打印函数)的方式来完成,这里需要获取的是应答头中特定的信息,比如应答码、cookies列表等,则需要通过下面这个函数:

CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); 

 info参数就是我们需要获取的内容,下面是一些参数值:

1.CURLINFO_RESPONSE_CODE
获取应答码
2.CURLINFO_HEADER_SIZE
头大小
3.CURLINFO_COOKIELIST
cookies列表

 除了获取应答信息外,这个函数还能获取curl的一些内部信息,如请求时间、连接时间等等。

五、多线程问题

 首先一个基本原则就是:绝对不应该在线程之间共享同一个libcurl handle(CURL *对象),不管是easy handle还是multi handle(本文只介绍easy_handle)。一个线程每次只能使用一个handle。
 libcurl是线程安全的,但有两点例外:信号(signals)和SSL/TLS handler。 信号用于超时失效名字解析(timing out name resolves)。
 libcurl依赖其他的库来支持SSL/STL,所以用多线程的方式访问HTTPS或FTPS的URL时,应该满足这些库对多线程 操作的一些要求。
 详细可以参考:
 OpenSSL: http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION

 GnuTLS: http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html

六、什么时候libcurl无法正常工作

 传输失败总是有原因的。你可能错误的设置了一些libcurl的属性或者没有正确的理解某些属性的含义,或者是远程主机返回一些无法被正确解析的内容。
 这里有一个黄金法则来处理这些问题:将CURLOPT_VERBOSE属性设置为1,libcurl会输出通信过程中的一些细节。如果使用的是http协 议,请求头/响应头也会被输出。将CURLOPT_HEADER设为1,这些头信息将出现在消息的内容中。
当然不可否认的是,libcurl还存在bug。
如果你对相关的协议了解越多,在使用libcurl时,就越不容易犯错。

七、关于密码

 客户端向服务器发送请求时,许多协议都要求提供用户名与密码。libcurl提供了多种方式来设置它们。
 一些协议支持在URL中直接指定用户名和密码,类似于: protocol://user:password@example.com/path/。libcurl能正确的识别这种URL中的用户名与密码并执行 相应的操作。如果你提供的用户名和密码中有特殊字符,首先应该对其进行URL编码。
 也可以通过CURLOPT_USERPWD属性来设置用户名与密码。参数是格式如 “user:password ”的字符串:
 curl_easy_setopt(easy_handle, CURLOPT_USERPWD, “user_name:password”);
 有时候在访问代理服务器的时候,可能时时要求提供用户名和密码进行用户身份验证。
 这种情况下,libcurl提供了另 一个属性CURLOPT_PROXYUSERPWD:
 curl_easy_setopt(easy_handle, CURLOPT_PROXYUSERPWD, “user_name:password”);
 在UNIX平台下,访问FTP的用户名和密码可能会被保存在$HOME/.netrc文件中。libcurl支持直接从这个文件中获取用户名与密码:
 curl_easy_setopt(easy_handle, CURLOPT_NETRC, 1L);
 在使用SSL时,可能需要提供一个私钥用于数据安全传输,通过CURLOPT_KEYPASSWD来设置私钥:
 curl_easy_setopt(easy_handle, CURLOPT_KEYPASSWD, “keypassword”);

八、HTTP验证

 在使用HTTP协议时,客户端有很多种方式向服务器提供验证信息。默认的 HTTP验证方法是"Basic”,它将用户名与密码以明文的方式、经Base64编码后保存在HTTP请求头中,发往服务器。当然这不太安全。
 当前版本的libcurl支持的验证方法有:basic, Digest, NTLM, Negotiate, GSS-Negotiate and SPNEGO。(译者感叹:搞Web这么多年,尽然不知道这些Http的验证方式,实在惭愧。)可以通过CURLOPT_HTTPAUTH属性来设置具体 的验证方式:
 curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
 向代理服务器发送验证信息时,可以通过CURLOPT_PROXYAUTH设置验证方式:
 curl_easy_setopt(easy_handle, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
 也可以同时设置多种验证方式(通过按位与), 使用‘CURLAUTH_ANY‘将允许libcurl可以选择任何它所支持的验证方式。
通过CURLOPT_HTTPAUTH或 CURLOPT_PROXYAUTH属性设置的多种验证方式,libcurl会在运行时选择一种它认为是最好的方式与服务器通信:
 curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
 // curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);

九、代码示例

1. 基本的http GET/POST操作

#include <stdio.h>
#include <curl/curl.h>
bool getUrl(char *filename)
{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指向的文件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)
{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");
}

2. 获取html网页

#include <stdio.h>
#include <curl/curl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{CURL *curl;             //定义CURL类型的指针
CURLcode res;           //定义CURLcode类型的变量,保存返回状态码if(argc!=2){printf("Usage : file <url>;\n");exit(1);}curl = curl_easy_init();        //初始化一个CURL类型的指针if(curl!=NULL){//设置curl选项. 其中CURLOPT_URL是让用户指 定url. argv[1]中存放的命令行传进来的网址curl_easy_setopt(curl, CURLOPT_URL, argv[1]);        //调用curl_easy_perform 执行我们的设置.并进行相关的操作. 在这 里只在屏幕上显示出来.res = curl_easy_perform(curl);//清除curl操作.curl_easy_cleanup(curl);}return 0;
}

3. 网页下载保存实例

// 采用CURLOPT_WRITEFUNCTION 实现网页下载保存功能
#include <stdio.h>;
#include <stdlib.h>;
#include <unistd.h>;#include <curl/curl.h>;
#include <curl/types.h>;
#include <curl/easy.h>;FILE *fp;  //定义FILE类型指针
//这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
//完成数据保存功能
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)  
{int written = fwrite(ptr, size, nmemb, (FILE *)fp);return written;
}int main(int argc, char *argv[])
{CURL *curl;curl_global_init(CURL_GLOBAL_ALL);  curl=curl_easy_init();curl_easy_setopt(curl, CURLOPT_URL, argv[1]);  if((fp=fopen(argv[2],"w"))==NULL){curl_easy_cleanup(curl);exit(1);}
CURLOPT_WRITEFUNCTION 将后继的动作交给write_data函数处理curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);  curl_easy_perform(curl);curl_easy_cleanup(curl);exit(0);
}

4. 进度条实例显示文件下载进度

// 采用CURLOPT_NOPROGRESS, CURLOPT_PROGRESSFUNCTION    CURLOPT_PROGRESSDATA 实现文件传输进度提示功能
//函数采用了gtk库,故编译时需指定gtk库
//函数启动专门的线程用于显示gtk 进度条bar
#include <stdio.h>
#include <gtk/gtk.h>
#include <curl/curl.h>
#include <curl/types.h> /* new for v7 */
#include <curl/easy.h> /* new for v7 */GtkWidget *Bar;
这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
//完成数据保存功能
size_t my_write_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
{return fwrite(ptr, size, nmemb, stream);
}
//这个函数是为了符合CURLOPT_READFUNCTION而构造的
//数据上传时使用
size_t my_read_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
{return fread(ptr, size, nmemb, stream);
}
//这个函数是为了符合CURLOPT_PROGRESSFUNCTION而构造的
//显示文件传输进度,t代表文件大小,d代表传 输已经完成部分
int my_progress_func(GtkWidget *bar,double t, /* dltotal */double d, /* dlnow */double ultotal,double ulnow)
{
/*  printf("%d / %d (%g %%)\n", d, t, d*100.0/t);*/gdk_threads_enter();gtk_progress_set_value(GTK_PROGRESS(bar), d*100.0/t);gdk_threads_leave();return 0;
}void *my_thread(void *ptr)
{CURL *curl;CURLcode res;FILE *outfile;gchar *url = ptr;curl = curl_easy_init();if(curl){outfile = fopen("test.curl", "w");curl_easy_setopt(curl, CURLOPT_URL, url);curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_func);curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read_func);curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, Bar);res = curl_easy_perform(curl);fclose(outfile);/* always cleanup */curl_easy_cleanup(curl);}return NULL;
}int main(int argc, char **argv)
{GtkWidget *Window, *Frame, *Frame2;GtkAdjustment *adj;/* Must initialize libcurl before any threads are started */curl_global_init(CURL_GLOBAL_ALL);/* Init thread */g_thread_init(NULL);gtk_init(&argc, &argv);Window = gtk_window_new(GTK_WINDOW_TOPLEVEL);Frame = gtk_frame_new(NULL);gtk_frame_set_shadow_type(GTK_FRAME(Frame), GTK_SHADOW_OUT);gtk_container_add(GTK_CONTAINER(Window), Frame);Frame2 = gtk_frame_new(NULL);gtk_frame_set_shadow_type(GTK_FRAME(Frame2), GTK_SHADOW_IN);gtk_container_add(GTK_CONTAINER(Frame), Frame2);gtk_container_set_border_width(GTK_CONTAINER(Frame2), 5);adj = (GtkAdjustment*)gtk_adjustment_new(0, 0, 100, 0, 0, 0);Bar = gtk_progress_bar_new_with_adjustment(adj);gtk_container_add(GTK_CONTAINER(Frame2), Bar);gtk_widget_show_all(Window);if (!g_thread_create(&my_thread, argv[1], FALSE, NULL) != 0)g_warning("can't create the thread");gdk_threads_enter();gtk_main();gdk_threads_leave();return 0;
}

5. 断点续传实例

//采用CURLOPT_RESUME_FROM_LARGE 实现文件断点续传功能
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>#include <curl/curl.h>
//这个函数为CURLOPT_HEADERFUNCTION参数构造
/* 从http头部获取文件size*/
size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream) {int r;long len = 0;/* _snscanf() is Win32 specific */// r = _snscanf(ptr, size * nmemb, "Content-Length: %ld\n", &len);r = sscanf(ptr, "Content-Length: %ld\n", &len);if (r) /* Microsoft: we don't read the specs */*((long *) stream) = len;return size * nmemb;
}/* 保存下载文件 */
size_t wirtefunc(void *ptr, size_t size, size_t nmemb, void *stream)
{return fwrite(ptr, size, nmemb, stream);
}/*读取上传文件 */
size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{FILE *f = stream;size_t n;if (ferror(f))return CURL_READFUNC_ABORT;n = fread(ptr, size, nmemb, f) * size;return n;
}// 下载 或者上传文件函数
int download(CURL *curlhandle, const char * remotepath, const char * localpath,long timeout, long tries)
{FILE *f;curl_off_t local_file_len = -1 ;long filesize =0 ;CURLcode r = CURLE_GOT_NOTHING;int c;struct stat file_info;int use_resume = 0;/* 得到本地文件大小 *///if(access(localpath,F_OK) ==0)if(stat(localpath, &file_info) == 0) {local_file_len =  file_info.st_size;use_resume  = 1;}//采用追加方式打开文件,便于实现文件断点续传工作f = fopen(localpath, "ab+"); if (f == NULL) {perror(NULL);return 0;}//curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, timeout);  // 设置连接超时,单位秒//设置http 头部处理函数curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &filesize);// 设置文件续传的位置给libcurlcurl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, use_resume?local_file_len:0);curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, f);curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc);//curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);//curl_easy_setopt(curlhandle, CURLOPT_READDATA, f);curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1L);curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);r = curl_easy_perform(curlhandle);fclose(f);if (r == CURLE_OK)return 1;else {fprintf(stderr, "%s\n", curl_easy_strerror(r));return 0;}
}int main(int c, char **argv) {CURL *curlhandle = NULL;curl_global_init(CURL_GLOBAL_ALL);curlhandle = curl_easy_init();//download(curlhandle, "ftp://user:pass@host/path/file", "C:\\file", 0, 3);download(curlhandle , "http://software.sky-union.cn/index.asp","/work/index.asp",1,3);curl_easy_cleanup(curlhandle);curl_global_cleanup();return 0;
}

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

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

相关文章

超聚变服务器(原华为服务器)网站模拟器

一、超聚变服务器&#xff08;原华为服务器&#xff09;网站模拟器&#xff1a; 原来了解服务器可以从他的网站上进行了解&#xff0c;模拟器做的很好了。 https://support.xfusion.com/server-simulators/ 有很多的模拟器&#xff0c;今天主要看下BMC的设置 有很多的在线工具…

XUbuntu22.04之HDMI显示器设置竖屏(一百九十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

谷歌宣布向云计算客户开放 Gemini Pro,开发者可用其构建应用

12 月 14 日消息&#xff0c;美国时间周三&#xff0c;谷歌宣布了一系列升级的人工智能&#xff08;AI&#xff09;功能&#xff0c;旨在为其云计算客户提供更好的服务。这家科技巨头正试图赶上竞争对手&#xff0c;比如微软和 OpenAI&#xff0c;它们都在积极利用人工智能的热…

Axure自定义元件

目录 1.processOne的使用 ​编辑2.自定义元件的使用、 2.1如何自定义一个元件 2.2使用自定义元件 导语&#xff1a; Axure是绘制原型图的软件&#xff0c;但是我们很多时候不知道&#xff0c;画哪一个板块&#xff0c;所以流程图的绘制也是非常重要的 1.processOne的使用…

【图论】普利姆算法,最小生成树

一次加入一个节点到我们的最下生成树中。加入哪个&#xff1f;跟着下面的步骤走一遍你就会了。 1. 把第一个节点A添加进来 2. 看两条边<A,B>,<A,E>,一个长度是3&#xff0c;一个长度是4&#xff0c;把长度短的边的另一个节点添加进来&#xff0c;也就是B 3. 再看A,…

oracle aq java jms使用(数据类型为XMLTYPE)

记录一次冷门技术oracle aq的使用 版本 oracle 11g 创建用户 -- 创建用户 create user testaq identified by 123456; grant connect, resource to testaq;-- 创建aq所需要的权限 grant execute on dbms_aq to testaq; grant execute on dbms_aqadm to testaq; begindbms_a…

超详细 | 哈里斯鹰优化算法原理、实现及其改进与利用(Matlab/Python)

测试函数为F9 在MATLAB中执行程序结果如下&#xff1a; 在Python中执行程序结果如下&#xff1a; 哈里斯鹰优化算法(Harris Hawks Optimization , HHO)是 Heidari等[1]于2019年提出的一种新型元启发式算法&#xff0c;设计灵感来源于哈里斯鹰在捕食猎物过程中的合作行为以及突…

flume系列之:监控flume agent channel的填充百分比

flume系列之:监控flume agent channel的填充百分比 一、监控效果二、获取flume agent三、飞书告警四、获取每个flume agent channel的填充百分比一、监控效果 二、获取flume agent def getKafkaFlumeAgent():# 腾讯云10.130.112.60zk = KazooClient(hosts

Day60力扣打卡

打卡记录 1682分了记录下&#xff0c;希望下回能突破1700捏。作为一个菜鸟&#xff0c;知道自己很菜&#xff0c;一步步走到现在还是很开心的&#xff0c;从以前的周赛稳定1题到稳定2题&#xff0c;到现在的时有时无的3题。每次刷题都期盼有所长进&#xff0c;虽然更多的时候收…

【C语言】字符串函数及其模拟实现

这是最好的时代&#xff0c;这是最坏的时代&#xff0c;我们一无所有&#xff0c;我们巍然矗立 本文由睡觉待开机原创&#xff0c;未经允许不得转载。 本内容在csdn网站首发 欢迎各位点赞—评论—收藏 如果存在不足之处请评论留言&#xff0c;共同进步&#xff01; 系列文章目录…

OpenSSL的源码在哪里下载?

官方网站去下载&#xff0c;网址&#xff1a; https://www.openssl.org/source/ 比较老的版本的下载页面地址&#xff1a; https://www.openssl.org/source/old/ 由于某面板的OpenSSL模块的安装配置语句如下&#xff1a; --with-openssl/root/rpmbuild/BUILD/openssl-1.0.2u所…

2-2基础算法-Nim和/前缀和/差分

文章目录 一.Nim和二.前缀和&区间和三.差分 一.Nim和 Nim游戏是一个数学策略游戏&#xff0c;通常涉及两名玩家轮流从几堆物品&#xff08;如石子或饼干&#xff09;中取走一定数量的物品。每个玩家每次可以从任意一堆中取走任意数量的物品&#xff0c;但必须至少取走一个…

使用qt实现四则运算计算机项目

这是我们要包含的头文件 #include <QWidget> #include<QStack> #include<string.h> #include<string> 这是我在ui界面创建的计算机基础框架。 接下来要实现按住每个按钮在白框内显示&#xff1b; 因此我们要定义一个QString 类型的变量 QString e…

Linux系统上64位ATT汇编语言多个源文件计算两个数的平方

运行程序的环境 sudo lsb_release -a看到操作系统是Ubuntu 22.04 LTS。 sudo uname -r看到内核版本是5.15.0-86-generic。 sudo as --version看到as的版本是2.38。 sudo ld --version看到ld的版本是2.38。 sudo gcc --version看到gcc版本是11.2.0。 sudo gdb --version看到gdb…

Yum仓库架构解析与搭建实践

1.Yum仓库搭建 1.1本地Yum仓库图解 1.2Linux本地仓库搭建 配置本地光盘镜像仓库 1&#xff09;挂载 [roothadoop101 ~]# mount -t iso996 /dev/cdrom/mnt 2&#xff09;查看 [rooothadoop101 ~] # df -h | |grep -i mnt /dev/sr0 4.6G 4.4G 3&#xf…

服务器上配置jupyter,提示Invalid credentials如何解决

我是按照网上教程在服务器上安装的jupyter以及进行的密码配置&#xff0c;我利用 passwd()这个口令生成的转译密码是"argon...."。按照教程配置jupyter notebook配置文件里面的内容&#xff0c;登陆网页提示"Invalid credentials"。我谷歌得到的解答是&…

学生选课系统基础版

目录 一.Java 中的集合框架&#xff08;上&#xff09; 1.Java中的集合框架概述 2.Collection接口&接口简介 3.学生选课——创建学生类和课程类 4.学生选课——添加课程Ⅰ 5.学生选课——添加课程Ⅱ 6.学生选课——课程查询 7.学生选课——课程修改 8.学生选课——课程删…

EduSoho教培系统 任意文件读取漏洞复现(CNVD-2023-03903)

0x01 产品简介 EduSoho教培系统是由杭州阔知网络科技有限公司研发的开源网校系统 0x02 漏洞概述 该教培系统classroom-course-statistics接口存在未授权任意文件读取漏洞,通过该漏洞攻击者可以读取到config/parameters.yml文件的内容,拿到该文件中保存的secret值以及数据库…

ShenYu网关Http服务探活解析

文章目录 网关端服务探活admin端服务探活 Shenyu HTTP服务探活是一种用于检测HTTP服务是否正常运行的机制。它通过建立Socket连接来判断服务是否可用。当服务不可用时&#xff0c;将服务从可用列表中移除。 网关端服务探活 以divide插件为例&#xff0c;看下divide插件是如何获…

Java监听器与观察者模式

Java监听器与观察者模式 Java中的监听器&#xff08;Listener&#xff09;和观察者模式&#xff08;Observer Pattern&#xff09;都是用于处理对象间的事件通知和响应的设计模式。它们的目的是在对象之间建立一种松散的耦合&#xff0c;使得一个对象的状态变化可以通知到其他…