curl与libcurl的关系
cURL是项目的名称。该名称是“ URL的客户端”上的一个名称,最初是用大写的URL拼写的,以使其明显地处理URL
cURL项目产生两种产品:
-
libcurl
一个免费且易于使用的客户端URL传输库,支持DICT,FILE,FTP,FTPS,GOPHER,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,MQTT,POP3,POP3S,RTMP,RTMPS,RTSP, SCP,SFTP,SMB,SMBS,SMTP,SMTPS,TELNET和TFTP。 -
curl
使用URL语法获取或发送文件的命令行工具
协议
DICT
- 字典是一种字典网络协议,它允许客户端向字典服务器询问单词的含义或解释。
- RFC 2229。
- 字典服务器和客户端使用TCP端口2628。
FILE
- FILE实际上不是一个“网络”协议。
- 它是一个URL方案,允许您告诉curl从本地文件系统获取文件,而不是通过网络从远程服务器获取文件。
- RFC 1738。
FTP
- FTP是文件传输协议(File Transfer Protocol)的缩写,是在客户机和服务器之间来回传输文件的一种古老(起源于20世纪70年代早期)方法。
- RFC 959。
- 这些年来,它已经大大扩展了。
- FTP服务器和客户端使用TCP端口21再加一个端口,第二个端口通常是在通信过程中动态建立的。
FTPS
- FTPS是安全文件传输协议。它遵循了在协议名称后面附加一个“S”的传统,表示该协议像普通的FTP一样完成,但添加了SSL/TLS安全层。
- RFC 4217。
GOPHER
- Gopher是为“在Internet上分发、搜索和检索文档”而设计的,它在某种程度上可以说是HTTP的鼻祖,因为HTTP基本上完全取代了相同的用例。
- Gopher服务器和客户机使用TCP端口70。
- RFC 1436。
GOPHERS
- Gopher带ssl,这是对旧协议的最新扩展。
HTTP
- 超文本传输协议HTTP是在web和Internet上传输数据最广泛使用的协议。
- 参见HTTP/1.1的RFC 7230和HTTP/2的RFC 7540。
- HTTP服务器和客户端使用TCP端口80。
HTTPS
- 安全HTTP是通过SSL/TLS连接完成的HTTP。
- RFC 2818。
- HTTPS服务器和客户端使用TCP端口443,除非他们使用HTTP/3,然后使用QUIC和UDP…
IMAP
- Internet消息访问协议(IMAP)是一个用于访问、控制和“阅读”电子邮件的协议。
- 参见RFC 3501。
- IMAP服务器和客户端使用TCP端口143。
- 当连接到服务器以明文开始时,SSL/TLS通信可能会被客户端使用STARTTLS命令显式请求升级连接。
- 参见RFC 2595
IMAPS
- 安全IMAP是通过SSL/TLS连接完成的IMAP。
- 这种连接隐式地开始使用SSL/TLS,因此服务器和客户端使用TCP端口993彼此通信。
- 参见RFC 8314。
LDAP
- 轻量级目录访问协议LDAP是一种用于访问和维护分布式目录信息的协议。基本上是 一个数据库查找。 参见RFC 4511。
- LDAP服务器和客户端使用的TCP端口为389
LDAPS
- 安全LDAP是通过SSL/TLS连接完成的LDAP。
MQTT
- 消息队列遥测传输(Message Queuing Telemetry Transport, MQTT)是一种在物联网系统中常用的协议,主要用于交换涉及较小设备的数据。
- 这就是所谓的“发布-订阅”协议。
POP3
- 邮局协议版本3 (POP3)是用于从服务器检索电子邮件的协议。参见RFC 1939。
- POP3服务器和客户端使用TCP端口110。
- 当与服务器的连接以明文开始时,客户端可能会使用STLS命令显式请求升级连接,从而支持SSL/TLS通信。参见RFC 2595。
POP3S
- 安全POP3是通过SSL/TLS连接完成的POP3。
- 这种连接隐式地开始使用SSL/TLS,因此服务器和客户端使用TCP端口995彼此通信。
- 参见RFC 8314。
RTMP
- 实时消息协议(RTMP)是一个用于音频、视频和数据流的协议。
- RTMP服务器和客户端使用TCP端口1935。
RTSP
- RTSP (Real Time Streaming Protocol)是一种用于控制流媒体服务器的网络控制协议。
- 参见RFC 2326。
- RTSP服务器和客户端使用TCP和UDP端口554。
SCP
- 安全复制(SCP)协议用于在远程SSH服务器之间复制文件。
- SCP服务器和客户机使用TCP端口22。
SFTP
- SFTP (SSH File Transfer Protocol)协议,通过可靠的数据流提供文件访问、文件传输和文件管理。
- SFTP服务器和客户端使用TCP端口22。
SMB
- SMB (Server Message Block)协议也称为CIFS。
- 它是一种应用层网络协议,主要用于在网络上的节点之间提供对文件、打印机、串口的共享访问和各种通信。
- SMB服务器和客户端使用TCP端口445。
SMTP
- SMTP (Simple Mail Transfer Protocol)是一种用于邮件传输的协议。
- 参见RFC 5321。
- SMTP服务器和客户端使用TCP端口25。
- 当连接到服务器以明文开始时,SSL/TLS通信可能会被客户端使用STARTTLS命令显式请求升级连接。
- 参见RFC 3207。
SMTPS
- 安全SMTP,有时称为SMTP,是通过SSL/TLS连接完成的SMTP。
- 这种连接隐式地开始使用SSL/TLS,因此服务器和客户端使用TCP端口465彼此通信。
- 参见RFC 8314。
TELNET(远程登陆)
- TELNET是一种应用层协议,使用虚拟终端连接在网络上提供双向交互式面向文本的通信设施。
- 参见RFC 854。
- TELNET服务器和客户端使用的TCP端口为23
TFTP
- 简单文件传输协议(TFTP)是一种协议,用于通过UDP进行简单的文件传输,从远程主机获取文件或将文件放到远程主机上。
- TFTP服务器和客户端使用的UDP端口为69。
环境
win10
直接下载工具包
下载:
https://curl.se/download.html, 找到合适的版本
然后解压缩
错误:
‘curl’ is not recognized as an internal or external command
解决:
然后把解压的路径C:\Users\oceanstar\software\curl-7.75.0-win64-mingw\bin放在system environment中的PATH中
测试:
源码编译
- 在开始菜单栏,找到VS2019,以管理员身份运行x64本机工具命令提示。
- 进入
C:\Users\admin\source\repos\curl-master\winbuild
,输入nmake /f Makefile.vc mode=static VC=19 MACHINE=x64 DEBUG=no ENABLE_IDN=no
,开始编译64位release的静态库。若编译32位,将x64改为x86;若编译debug版本,将no改为yes;若编译动态库,将static
改为dll
;若为其他版本的VS,将19改为你VS版本对应值。
- 说明:使用 nmake 编译 libcurl 时,出现提示:
libcurl_a_debug.lib(idn_win32.obj) : error LNK2019: 无法解析的外部符号 __imp__IdnToAscii@20,该符号在函数 _curl_win32_idn_to_ascii 中被引用
libcurl_a_debug.lib(idn_win32.obj) : error LNK2019: 无法解析的外部符号 __imp__IdnToUnicode@20,该符号在函数 _curl_win32_ascii_to_idn 中被引用
..\builds\libcurl-vc9-x86-debug-static-ipv6-sspi-winssl\bin\curl.exe : fatal error LNK1120: 2 个无法解析的外部命令
NMAKE : fatal error U1077: “"D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\link.exe"”: 返回代码“0x460”
Stop.
NMAKE : fatal error U1077: “"D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\nmake.exe"”: 返回代码“0x2”
Stop.
- 导致外部程序(使用了libcurl )在编译时,出现以下错误提示:
1>libcurld.lib(idn_win32.obj) : error LNK2019: 无法解析的外部符号 __imp__IdnToAscii@20,该符号在函数 _curl_win32_idn_to_ascii 中被引用
1>libcurld.lib(idn_win32.obj) : error LNK2019: 无法解析的外部符号 __imp__IdnToUnicode@20,该符号在函数 _curl_win32_ascii_to_idn 中被引用
- 解决方案: 在使用nmake进行编译时,输入的命令为:
nmake /f makefile.vc mode=static VC=9 ENABLE_IDN=no debug=no
。如果没有指定ENABLE_IDN=no,则默认按照ENABLE_IDN=yes进行编译。从而在编译libcurl时出现了之前的提示,接着导致程序在使用libcurl库时出现错误提示!
- 至此,库已经编译完成。
linux
1、选择最新版本的压缩文件下载
2、安装
# wget https://curl.haxx.se/download/ curl-7.75.0.tar.gz
tar -xvf curl-7.75.0.tar.gz
cd curl-7.75.0/
./configure
make
make test (optional)
sudo make install
注意: ./configure 报错
error: no acceptable C compiler found in $PATH
说明没有安装GCC:
yum -y install gcc
3.命令测试
测试curl命令是否可用
# curl
curl: try 'curl --help' or 'curl --manual' for more information
若curl命令不可用,则通过shell指定命令的位置(此处已经知道命令被安装到/usr/local/bin位置)
export PATH=$PATH:/usr/local/bin
4.库、头文件和命令的安装位置
# 已安装的libcurl版本是什么
$ curl-config --version
libcurl 7.75.0
$ curl-config --cflags
-I/usr/local/include
$ curl-config --libs
-L/usr/local/lib -lcurl
$ ls /usr/local/include/
curl
ls /usr/local/lib
libcurl.so.4 libcurl.so.4.7.0 libcurl.a libcurl.la libcurl.so pkgconfig
测试
windows
(1)创建工程
(2)将上面生成的三个目录放到include、bin、lib目录下
(3)设置项目属性
(4)测试代码
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "libcurl_a.lib")
#define BUILDING_LIBCURL
#define HTTP_ONLY
#define CURL_STATICLIB
#include <curl/curl.h>
int main() {
CURL* curl = curl_easy_init();
if (curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return 0;
}
post,json请求
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "libcurl_a_debug.lib")
#define BUILDING_LIBCURL
#define HTTP_ONLY
#define CURL_STATICLIB
#define IMAGE_SIZE 1920 * 1080 * 3
#define logger_fatal printf
#define logger_info printf
#define logger_debug printf
#define logger_error printf
#include <string>
#include <curl/curl.h>
size_t OnWirteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
if ( NULL == buffer)
{
return -1;
}
logger_error("%s, %s(%d):buffer: %lld, %lld, %s\r\n", __FILE__, __FUNCTION__, __LINE__, size, nmemb, (char *)buffer);
return nmemb;
}
int Post(const char * strUrl, const char* strPost)
{
CURLcode res = CURLE_OK;
CURL* curl = curl_easy_init();
if (NULL == curl)
{
return CURLE_FAILED_INIT;
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, "Content-Type:application/json;charset=UTF-8"));
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWirteData);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20);//连接时间
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int main(int argc, char const* argv[]) {
curl_global_init(CURL_GLOBAL_ALL);
int ret = 0;
char* str = { 0 };
str = (char*)calloc(1, IMAGE_SIZE);
if (str == NULL) {
logger_error("%s, %s(%d): malloc failed\r\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
}
char * imagesrc = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKKKAP/2Q==";
sprintf_s(str, IMAGE_SIZE, "{\"camera_id\":\"%s\",\"iswarm\":\"1\",\"media_type\":\"jpeg\",\"imagesrc\":\"%s\",\"casekind\": %d, \"is_finish\": true}",
"123456", imagesrc, 1);
int res = Post("http://192.168.0.71:8080/alert/push", str);
logger_info("Post Statu = %d", res);
free(str);
curl_global_cleanup();
system("pause");
return 0;
}
linux
1、CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(libcuul_study)
set(CMAKE_CXX_STANDARD 11)
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} curl)
2、main.cpp
#include <curl/curl.h>
int main() {
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return 0;
}
两种界面
简单界面
easy界面是一个同步,搞笑,快速使用的用于文件传输的简单界面
概述
- 当使用libcurl的”简单“界面时,您将启动会话并获得一个句柄(通过curl_easy_init获得),将其用作所使用的简易界面功能的输入
- 继续使用curl_easy_setopt设置即将到来的传输中所需的所有选项,其中最重要的是指定URL本身。您可能还希望设置一些回调,这些回调将在有数据可用时从库中调用
- 设置完毕后,您告诉libcurl使用curl_easy_perform执行传输。然后它将完成整个操作,直到完成(成功或失败)后,它才返回。
- 进行传输后,您可以设置新选项并进行另一次传输,或者,如果完成,可以通过调用curl_easy_cleanup清理会话。如果需要持久连接,则无需立即清除,而要使用相同的简单句柄继续运行并执行其他传输
多接口界面
多重界面提供了简易界面所没有的几种功能。它们主要是:
- 启动”pull“界面。使用libcurl的应用程序决定在那里以及何时要求
libcurl
获取/发送数据 - 在同一线程中启用多个同时传输,而不会使得应用程序复杂
- 使应用程序可以等待同时会其自己的文件描述符和curl的文件描述符进行操作
- 启用基于事件的处理和扩展传输,扩展到成千上万的并行连接
如何使用
- 要使用多重接口,必须首先使用curl_multi_init创建一个”多重句柄“。然后使用此句柄作为所有其他curl_multi_ *函数的输入。
- 使用多句柄和多接口,可以并行的进行多个同时传输。每次单词传输都围绕一个简单的句柄进行。您将创建所需的所有便捷句柄,并使用curl_easy_setopt为每个便捷手柄设置适当的选项。
- 多重借口有两种:
- 面向select的
- 基于事件的
- 当设置好简易句柄并准备好进行传输时,应该使用
curl_multi_add_handle
将简易句柄添加到多句柄中,而不是使用curl_easy_perform
。您可以随时在多句柄中添加更多简单的句柄,即使其他传输已在运行中也是如此。 - 如果您改变主意,则可以使用curl_multi_remove_handle从多堆栈中再次删除。从多手柄中移除后,您可以再次使用其他简单的界面功能,您可以在传输过程中的任何时间点删除句柄。
- 将easy-handler添加到multi-handler不会启动传输。请记住,使用此接口的主要思想之一就是让你的应用程序驱动。您可以通过调用curl_multi_perform驱动传输。如果有任何可传输的内容,那么libcurl将传输数据。它将使用回调以及您在单个简单句柄中设置的所有其他内容。他会在多堆栈中所有准备进行任何传输的当前传输中传输数据。可能是全部,也可能没有。当目前没有其他事情要做时,它将返回到调用应用程序
API
curl_multi_init
#include <curl/curl.h> CURLM * curl_multi_init();
作用:
- 创建一个多句柄
描述:
- 此函数返回一个CURLM句柄,以用作其他多功能的输入
- 操作完成后,此init调用必须具有对curl_multi_cleanup的相应调用。
返回值:
- 如果此函数返回NULL,则出问题了,您将无法使用其他curl函数
curl_multi_cleanup
#include <curl/curl.h> CURLMcode curl_multi_cleanup(CURLM * multi_handle)
作用:
- 关闭多会话
描述:
- 清理并删除整个多堆栈。它不会以任何方式释放简单句柄(仍然需要使用通常的curl_easy_cleanup方法单独关闭它们)。清理顺序:
- curl_multi_remove_handle在清理任何简单的句柄之前
- 现在可以独立调用curl_easy_cleanup,因为easy句柄不再连接到multi句柄
- 移除所有简单句柄时应调用 curl_multi_cleanup
curl_multi_wait
作用:
- 轮询多句柄中的所有简单句柄
描述:
- 轮询多句柄中的所有简单句柄。阻塞直到在至少一个句柄上检测到活动或者
timeout_ms
已经过去。或者如果多句柄的未决内部超时的到期时间比timeout_ms
短,则将用较短的时间来确保合理的保持超时精度
curl_multi_add_handle
#include <curl / curl.h>
CURLMcode curl_multi_add_handle(CURLM * multi_handle,CURL * easy_handle);
作用:
- 向多会话添加简单句柄
描述:
- 向都堆栈添加一个标准的简单句柄。此函数调用将使此multi_handle控制指定easy_handler
- 当简单句柄添加到多堆栈后,一定不要将该句柄上使用curl_easy_perform。再次从多堆栈中移除了easy句柄之后,再次将其与easy接口一起使用是完全可以的。
curl_multi_remove_handle
curl_multi_remove_handle
作用:
- 从多会话中删除一个简单的句柄
描述:
- 从multi_handler删除一个给定的easy_handler
- 从多个堆栈中删除了easy句柄后,再次在此easy句柄上调用curl_easy_perform是完全合法的。
- 在使用过程中删除易用的手柄是完全合法的,这将有效地停止涉及该易用手柄的正在进行的传输。所有其他简单的操作和转移将不受影响。
- 可以在传输过程中随时删除句柄,只是不要从任何libcurl回调函数中删除句柄
curl_multi_perform
作用:
- 从每个简单句柄中读取/写入可用数据
描述:
- 此函数此非阻塞方式处理所有需要注意添加的句柄上的传输
- 当此函数返回时将running_handles设置为零(0)时,将不再进行任何传输。
curl_multi_info_read
作用:
- 读取多堆栈信息
描述:
- 询问多功能句柄,是否有来自各个传输的信息。
- 重复调用此函数每次都会返回一个新的结构,直到返回NULL作为信号为止没有更多的可用。
msgs_in_queue
指向的整数将包含调用此函数后剩余的消息数 - 使用此函数获取消息时,该消息将从内部队列中删除,因此再次调用此函数将不会再次返回同一消息,而是返回新消息,直到队列清空
- 注意:返回的指针指向的数据无法继续调用curl_multi_cleanup,curl_multi_remove_handle或curl_easy_cleanup。
- “ CURLMsg”结构非常简单,仅包含非常基本的信息。如果需要更多涉及的信息,使用
curl_easy_getinfo
:
struct CURLMsg {
CURLMSG msg; /* 此消息的含义*/
CURL *easy_handle; /* 所涉及的句柄, 用于获取详细信息 */
union {
void *whatever; /* 特定于消息的数据 */
CURLcode result; /* 返回代码,用于传输*/
} data;
};
- 当msg为CURLMSG_DONE时,该消息标识已完成的传输,然后结果包含刚刚完成的简单句柄的返回码。
curl_multi_setopt
#include <curl/curl.h>
CURLMcode curl_multi_setopt(CURLM * multi_handle, CURLMoption option, param);
作用:
- 设置curl多手柄的选项,用于告诉libcurl多句柄如何运行
CURLMOPT_PIPELINING
#include <curl / curl.h>
CURLMcode curl_multi_setopt(CURLM * handle,CURLMOPT_PIPELINING,long bitmask);
作用:
- 启用HTTP流水线和多路复用
描述:
- 启动后,libcurl将对同一主机进行并行请求时尝试使用那些协议功能。
- 对于流水线,这意味着,如果添加可以使用现有连接的第二个请求,则第二个请求将在同一连接上“流水线”,而不是并行执行。
- 对于多路复用,这意味着后续请求可以重新使用现有连接,并在其他传输已经使用该单个连接的同时,发送多路复用的新请求。
CURLMOPT_MAX_TOTAL_CONNECTIONS
#include <curl/curl.h>
CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, long amount);
作用:
- 同时打开的最大连接数。
- 达到限制后,会话将处于待处理状态,直到有可用的连接为止。如果启用了CURLMOPT_PIPELINING,则libcurl将尝试通过管道传输或在主机支持的情况下使用多路复用。
- 默认值为0,表示没有限制
例子:
CURLM * m = curl_multi_init();
/*永远不要进行超过15个连接*/
curl_multi_setopt(m,CURLMOPT_MAX_TOTAL_CONNECTIONS,15L);
CURLMOPT_MAXCONNECTS
#include <curl / curl.h>
CURLMcode curl_multi_setopt(CURLM * handle,CURLMOPT_MAXCONNECTS,long max);
作用:
- 设置连接缓存的大小
描述:
- 设置的数量将用作libcurl在完全使用后可以保留在其连接缓存中的同时打开的连接的最大数量
- 通过设置此选项,可以防止缓存大小超过您设置的限制。
- 当缓存已满时,curl关闭缓存中最旧的缓存,以防止打开的连接数增加。
例子:
CURLM * m = curl_multi_init();
/ *仅在高速缓存中保留10个连接* /
curl_multi_setopt(m,CURLMOPT_MAXCONNECTS,10L);
curl_global_init
#include <curl/curl.h> CURLcode curl_global_init(long flags);
作用:
- 全局libcurl初始化
描述:
- 此函数设置libcurl所需的程序环境。可以将其视为库加载器的扩展
- 在程序调用libcurl中的任何其他函数之前,该函数必须在程序中至少被调用一次(程序是共享内存空间的所有代码)。它设置的环境在程序的生命周期中是恒定的,并且对于每个程序都是相同的,因此多次调用与一次调用具有相同的效果
- flags是一种位模式,它可以告诉libcurl确切的初始化功能,如下所述,通过对这些值进行“或”运算来设置所需的位。在正常操作中,您必须指定CURL_GLOBAL_ALL。除非您熟悉它并打算控制libcurl的内部操作,否则请不要使用任何其他值
- 此函数不是线程安全的
curl_easy_init、curl_easy_cleanup
原型:
#include <curl/curl.h> CURL *curl_easy_init( );
作用:
- 创建一个简单的句柄,用来启动一个libcurl会话
描述:
- 此函数必须是第一个要调用的函数,它返回一个curl简易句柄,您必须使用它作为easy界面中其他函数的输入。
- 操作完成后,此调用必须具有对
curl_easy_cleanup
的相应调用- 如果尚未调用curl_global_init,curl_easy_init会自动执行此操作。这在多线程情况下可能是致命的,因为curl_global_init不是线程安全的,并且由于没有相应的清理,可能会导致资源问题
- 强烈建议您自己正确调用
curl_global_init
来禁止这种自动行为。有关如何使用此功能的详细信息,请参见libcurl(3)中的全局环境要求的描述。返回值:
- 如果此函数返回NULL,则表示错误,您将无法使用其他curl函数。
原型:
#include <curl/curl.h> void curl_easy_cleanup(CURL * handle )
作用:
- 销毁一个简单的句柄,结束一个libcurl会话
描述:
- 此函数必须是调用简单会话的最后一个函数
- 这可能会关闭此手柄使用过的所有连接,并且可能移植保持打开状态-除非在进行传输时将其连接到多手柄上。如果要传输更多文件,请不要调用此函数,重新使用句柄是libcurl取得良好性能的关键
- 有时,您可能会从curl_easy_cleanup(如果先前使用curl_easy_setopt为该句柄设置)中调用了进度回调或标头回调。就像libcurl决定关闭连接,而协议属于那种在断开连接之前需要命令/响应序列的协议。此类协议的示例是FTP,POP3和IMAP。
- 在调用此函数并返回后,对句柄的任何使用都是非法的。curl_easy_cleanup会杀死该句柄以及与此相关的所有内存!
- 在handle中传递NULL指针将使此函数立即返回而无需执行任何操作
返回值:
- 无
- 例子:
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
curl_easy_perform
原型:
#include <curl/curl.h> CURLcode curl_easy_perform(CURL *easy_handle);
作用:同步执行文件传输
描述:
- 在curl_easy_init和所有curl_easy_setopt调用完成后调用此函数,并按照选项中的说明执行传输。
- curl_easy_perform以阻塞方式执行整个请求,并在完成或失败时返回。有关非阻塞行为,请参见
curl_multi_perform
。- 您可以在使用相同的easy_handle的同时对curl_easy_perform进行任意数量的调用。如果您打算传输多个文件,甚至会被鼓励这样做。然后,libcurl将尝试在以后的传输中重新使用相同的连接,从而使操作更快,CPU占用更少并占用更少的网络资源。请注意,在调用之间必须使用
curl_easy_setopt
来设置以下curl_easy_perform的选项。- 您绝不能使用相同的easy_handle从两个位置同时调用此函数。让函数先返回,然后再调用它。如果要并行传输,则必须使用多个curl easy_handles。
返回值:
- CURLE_OK(0)表示一切正常,非零表示<curl / curl.h>定义时发生错误-请参见
libcurl-errors
- 如果使用curl_easy_setopt设置了
CURLOPT_ERRORBUFFER
,则返回非零值时,错误缓冲区中将出现可读的错误消息。
- 例子:
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
curl_easy_reset
原型:
#include <curl / curl.h> void curl_easy_reset(CURL * handle );
作用:
- 重置libcurl会话句柄的所有选项
- 它不会更改句柄中保留的以下信息:实时连接,会话ID缓存,DNS缓存,cookie,共享或alt-svc缓存。
curl_easy_duphandle
原型:
#include <curl / curl.h> CURL * curl_easy_duphandle(CURL * handle );
作用:
- 克隆一个libcurl会话句柄,返回一个新的curl手柄,随后可以独立使用两个句柄,并且必须使用curl_easy_cleanup释放它们。
- 新句柄也指向之前用curl_easy_setopt设置的url,但是会清空所有先前设置的选项
- 新的句柄将不会继承任何状态信息,没有连接,没有SSL会话以及没有cookie。它也不会继承任何共享对象的状态或选项(就像CURLOPT_SHARE设置为NULL一样)
- 在多线程程序中,必须以同步方式调用此函数,克隆后可能不使用输入句柄。
返回值:
- 如果此函数返回NULL,则出了点问题,并且没有返回有效的句柄。
curl_easy_setopt
原型:
#include <curl/curl.h> CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
作用:
- 设置curl句柄的选项
描述:
- curl_easy_setopt告诉libcurl如何运行。通过设置适当的选项,应用程序可以更改libcurl的行为。
- 使用此函数调用设置的选项对于使用此句柄执行的所有即将进行的传输均有效。传输之间不会以任何方式重置这些选项,因此,如果要使用不同的选项进行后续传输,必须在传输之间进行更改。您可以使用
curl_easy_reset
将所有选项重置为内部默认值- 设置选项的顺序无关紧要。\
行为选项 | |
---|---|
CURLOPT_VERBOSE | 显示详细信息 |
CURLOPT_HEADER | 在正文输出中包含标题 |
CURLOPT_NOPROGRESS | 关闭进度条 |
CURLOPT_NOSIGNAL | 不要安装信号处理程序 |
CURLOPT_WILDCARDMATCH | 启用目录通配符传输 |
网络选项 | |
---|---|
CURLOPT_URL | 提供要在请求中使用的URL |
CURLOPT_URL
使用:
#include <curl/curl.h> CURLcode curl_easy_setopt(CURL * handle,CURLOPT_URL,char * URL);
作用:
- 设置目标网址
- 必须设置的唯一选项,否则将无法进行传输
CURLOPT_VERBOSE
使用:
#include <curl/curl.h> CURLcode curl_easy_setopt(CURL *handle, CURLOPT_VERBOSE, long onoff);
作用:
- 启动/禁用详细模式。
描述:
- 将onoff参数设置为1,以使库在该句柄上显示很多有关其操作的详细信息。对于libcurl或其他协议调试和理解非常有用。
- 将onoff参数设置为0,关闭详细输出,默认设置为0。
- 详细信息将发送到
stderr
或使用CURLOPT_STDERR
设置的流- 要获取所有发送和接收的协议数据,请考虑使用
CURLOPT_DEBUGFUNCTION
。
#include <curl/curl.h>
int main() {
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");
// 请libcurl向我们显示详细输出
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// 执行请求
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return 0;
}
CURLOPT_HEADER
使用:
#include <curl/curl.h> CURLcode curl_easy_setopt(CURL * handle,CURLOPT_HEADER,long onoff);
作用:
- 将标头传递到数据流
描述:
- 将onoff参数设置为1,以要求libcurl在写回调(CURLOPT_WRITEFUNCTION)中包含标头。此选项与实际上具体标头或其他元数据(比如HTTP和FTP)的协议有关
- 当要求将标头传递给与正文相同的回调时,如果没有关于所使用协议的详细知识,就不可能再次正确地分离它们。
#include <curl/curl.h>
int main() {
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
// 执行请求
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return 0;
}
CURLOPT_NOPROGRESS
#include <curl / curl.h> CURLcode curl_easy_setopt(CURL * handle,CURLOPT_NOPROGRESS,long onoff);
作用:
- 关闭进度条
描述:
- onoff=1时,它会通知库针对使用此handler完成的请求完全关闭进度条。它还将防止调用CURLOPT_XFERINFOFUNCTION或CURLOPT_PROGRESSFUNCTION
#include <curl/curl.h>
int main() {
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");
//启用进度表
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
// 执行请求
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return 0;
}
CURLOPT_NOSIGNAL
作用:
- 跳过所有信号处理
描述:
- 如果onoff为1,libcurl将不使用任何安装信号处理程序的函数或任何导致向进程发送信号的函数。
- 此选项允许多线程unix应用程序仍然设置/使用所有超时选项等,而不冒获取信号的风险。
- 如果设置了此选项并且libcurl是使用标准名称解析程序生成的,则在进行名称解析时不会发生超时。
- 考虑使用c-ares或线程解析器后端构建libcurl,以启用异步DNS查找,从而在不使用信号的情况下为名称解析启用超时。
- 将CURLOPT_NOSIGNAL设置为1将使libcurl不要求系统忽略SIGPIPE信号,否则,在尝试向另一端关闭的套接字发送数据时,系统会发送SIGPIPE信号。libcurl努力避免触发这样的SIGPIPEs,但是有些操作系统无法避免它们,甚至在那些有SIGPIPEs的操作系统上,也有一些死角的情况,它们可能仍然会发生,这与我们的愿望相反。此外,使用CURLAUTH\u NTLM\u WB身份验证可能会引发SIGCHLD信号。
CURLOPT_NOBODY
- 设置为1的long参数会告诉libcurl在进行下载时不将主体部分包含在输出中。对于HTTP(S),这使libcurl进行HEAD请求。对于大多数其他协议,这意味着不要求传输主体数据。
CURLOPT_WRITEFUNCTION
作用:
- 设置写接收数据的回调
CURLOPT_PRIVATE
#include <curl / curl.h>
CURLcode curl_easy_setopt(CURL * handle,CURLOPT_PRIVATE,void * pointer);
作用:
- 存储私有指针
描述:
传递一个void * 作为参数,指向与此handler相关联的数据。我们可以使用curl_easy_getinfo与CURLINFO_PRIVATE选项读取。libcurl本身永远不会对这些数据做任何事情
CURLOPT_INFILESIZE_LARGE
作用:
- 设置要发送的输入文件的大小
描述:
- 将文件上传到远程站点时,应使用filesize告诉libcurl输入文件的预期大小。该值必须作为curl_off_t传递
- 要再次取消设置该值,请将其设置为-1。
CURLOPT_UPLOAD
描述:
- 1表示库准备上传数据,默认0表示下载数据
- 如果协议是HTTP,则上载意味着使用PUT请求,除非您另行告知libcurl
CURLOPT_HEADERFUNCTION
作用:
- 接收标头数据的回调
- 接收到标头数据后,libcurl会立即调用此函数。标头回调将为每个标头调用一次,并且只有完整的标头行会传递给该回调。解析标头非常容易。缓冲区指向所传递的数据,该数据的大小为nitems;size始终为1。请勿假设标题行以null终止!
CURLOPT_HEADER
作用:
- 将标头传递到数据流
CURLOPT_SHARE
#include <curl / curl.h>
CURLcode curl_easy_setopt(CURL * handle,CURLOPT_SHARE,CURLSH * share);
作用:
- 指定要使用的共享句柄
描述:
- 传递共享句柄作为参数。
- 共享句柄必须已经先前由对curl_share_init的调用创建
- 设置此选项,将使此curl句柄使用共享句柄中的数据,而不是将数据保留给自己。
CURLOPT_ALTSVC
作用:
- 设置alt_svc缓存文件名
描述:
- 传递指向文件名的指针,以指示libcurl将该文件用作Alt-Svc缓存,以从传输中读取现有的缓存内容,也可以在传输后将其写回到,除非在CURLOPT_ALTSVC_CTRL中设置了CURLALTSVC_READONLYFILE
- 默认"",alt-svc缓存既不读取也不写入文件。
- 仅HTTPS支持
CURLOPT_ALTSVC_CTRL
作用:
- 控制alt-svc行为
示例:
#include <stdio.h>
#include <curl/curl.h>
// 带有Alt-Svc支持的HTTP
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl){
// 在此文件中缓存替代项
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
// 限制使用替代版本的HTTP
curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, (long)
CURLALTSVC_H1|CURLALTSVC_H2|CURLALTSVC_H3);
//执行请求,res将获得返回码
res = curl_easy_perform(curl);
// 检查错误
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
// 总是清理
curl_easy_cleanup(curl);
}
return 0;
}
curl_easy_getinfo
作用:
- 从curl句柄中提取信息
CURLINFO_PRIVATE
CURLINFO_SPEED_UPLOAD_T
作用: 获取上传速度
描述:
- 将指针传递给curl_off_t,以接收为完整上传测得curl的平均上传速度。以字节/秒为单位
CURLINFO_TOTAL_TIME_T
作用:
- 以ms为单位获取上一次传输的总时间
描述:
- 将指针传递给curl_off_t以接收上一次传输的总时间,包括名称解析,TCP连接等。curl_off_t表示时间(以微秒为单位)。
- 当遵循重定向时,来自每个请求的时间将加在一起。
示例
上传文件
#include <stdio.h>
#include <curl/curl.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FILE_PATH "/home/oceanstar/CLionProjects/acl_redis.tar.gz"
#define UPLOAD_URL "file:///home/oceanstar/cutimage"
int main(int argc, char *argv[]) {
CURL *curl;
CURLcode res;
struct stat file_info;
curl_off_t speed_upload, total_time;
FILE *fd;
fd = fopen(FILE_PATH, "rb");
if (fd) {
return 1;
}
if (fstat(fileno(fd), &file_info) != 0) {
return 1;
}
curl = curl_easy_init();
if (curl) {
// 上传到这个地方
curl_easy_setopt(curl, CURLOPT_URL,
UPLOAD_URL);
// 告诉库将要上传数据
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// 设置读取位置(在Windows上也需要使用READFUNCTION)
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
// 并给出上传的大小(可选)
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
(curl_off_t) file_info.st_size);
// 启用冗长以便于跟踪
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}else{
//现在提取传输信息
curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD_T, &speed_upload);
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &total_time);
fprintf(stderr, "Speed: %" CURL_FORMAT_CURL_OFF_T " bytes/sec during %"
CURL_FORMAT_CURL_OFF_T ".%06ld seconds\n",
speed_upload,
(total_time / 1000000), (long)(total_time % 1000000));
}
}
fclose(fd);
return 0;
}
从ftp服务器获取单个文件到本地
#include <stdio.h>
#include <curl/curl.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FTP_SERVER "ftp://127.0.0.1/home/oceanstar/CLionProjects/acl_redis.tar.gz" //"ftp://127.0.0.1/home/data/cutimage/file.txt"
#define LOCAL_NAME "/home/oceanstar/CLionProjects/libcuul_study/build/new_name.tar.gz"
struct FtpFile{
const char *filename;
FILE *stream;
};
static size_t my_fwrite(void *buffer, size_t size, size_t nmemb,
void *stream){
struct FtpFile *out = (struct FtpFile *)stream;
if(!out->stream){
// 打开文件用于写入
out->stream = fopen(out->filename, "wb");
if(!out->stream){
return -1; // 失败,无法打开文件写入
}
}
return fwrite(buffer, size, nmemb, out->stream);
}
int main(int argc, char *argv[]) {
CURL *curl;
CURLcode res;
struct FtpFile ftpfile = {
LOCAL_NAME,
NULL
};
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl){
curl_easy_setopt(curl, CURLOPT_URL, FTP_SERVER);
// 定义我们的回调函数,以便在有数据要写入时被调用
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
//设置指向我们的结构的指针以传递给回调
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
//激活SSL,并且需要它同时用于控制和数据
//curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
// 打开完整的协议/调试输出
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if(CURLE_OK != res) {
/* we failed */
fprintf(stderr, "curl told us %d\n", res);
}
}
if(ftpfile.stream)
fclose(ftpfile.stream); /* close the local file */
curl_global_cleanup();
return 0;
}
获取ftp服务器上远程文件的文件大小和创建时间
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#define FTP_SERVER "ftp://127.0.0.1/home/oceanstar/CLionProjects/acl_redis.tar.gz"
static size_t throw_away(void *ptr, size_t size, size_t nmemb, void *data)
{
(void)ptr;
(void)data;
/* we are not interested in the headers itself,
so we only return the size we would have saved ... */
return (size_t)(size * nmemb);
}
int main(int argc, char *argv[]) {
char ftpurl[] = FTP_SERVER;
CURL *curl;
CURLcode res;
long filetime = -1;
double filesize = 0.0;
const char *filename = strrchr(ftpurl, '/') + 1;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl){
curl_easy_setopt(curl, CURLOPT_URL, ftpurl);
//
curl_easy_setopt(curl, CURLOPT_NOBODY, 1l);
//询问文件时间
curl_easy_setopt(curl, CURLOPT_FILETIME, 1L);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, throw_away);
curl_easy_setopt(curl, CURLOPT_HEADER, 0L);
//打开完整的协议/调试输出
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if(CURLE_OK == res) {
res = curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
if((CURLE_OK == res) && (filetime >= 0)) {
time_t file_time = (time_t)filetime;
printf("创建时间 %s: %s", filename, ctime(&file_time));
}
res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD,
&filesize);
if((CURLE_OK == res) && (filesize>0.0))
printf("文件大小 %s: %0.0f bytes\n", filename, filesize);
}else {
fprintf(stderr, "curl told us %d\n", res);
}
curl_easy_cleanup(curl);
}
return 0;
}
完成传输后,使用getinfo获取内容类型
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/");
res = curl_easy_perform(curl);
if(CURLE_OK == res) {
char *ct;
/* ask for the content-type */
res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct);
if((CURLE_OK == res) && ct)
printf("We received Content-Type: %s\n", ct);
}
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
在ftp/ftps服务器上面创建目录
#include <iostream>
#include <string.h>
#include <curl/curl.h>
int main()
{
char temp[2000];
struct curl_slist *headerlist=NULL;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "ftp://admin:123456@192.168.1.150");
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
//下面3行是针对ssl
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
snprintf(temp, sizeof(temp), "MKD FTP_DIR");/* 执行的命令 创建FTP_DIR目录 */
headerlist = curl_slist_append(headerlist, temp);
curl_easy_setopt(curl, CURLOPT_QUOTE, headerlist);/* CURLOPT_QUOTE 对应的是命令行选项*/
CURLcode res = curl_easy_perform(curl);
curl_slist_free_all (headerlist);
curl_global_cleanup();
if(res == CURLE_OK) std::cout << "mkdir succ\n";
else std::cout << "mkdir fail " << res << std::endl;
}
查询ftp/ftps服务器下的文件
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
int main(int argc, char *argv[]) {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl){
curl_easy_setopt(curl, CURLOPT_URL, "ftps://dss:admin12345@192.113.115.28" );
// curl_easy_setopt(curl, CURLOPT_URL, "ftps://192.113.115.28" );
// curl_easy_setopt(curl, CURLOPT_USERPWD, "dss:admin12345");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
res = curl_easy_perform(curl);
if(CURLE_OK == res) {
printf("-----ok");
}else {
fprintf(stderr, "-------curl told us %d\n", res);
}
curl_easy_cleanup(curl);
}
return 0;
}
封装
class CHttpCurl
{
public:
CHttpCurl(void);
~CHttpCurl(void);
/**
*@brief HTTP POST请求
*@param strUrl 输入参数,请求Url地址,如:http://www.baidu.com
*@param strPost 输入参数,使用如下格式:para1=val1?2=val2
*@param strResponse 输出参数,返回内容
*@return 返回是否Post成功
*/
int Post(const std::string& strUrl,const std::string& strPost,std::string& strResponse);
int PostFile(const std::string &strUrl, const std::string &strFileName, std::string &strResponse);
/**
*@brief HTTP GET请求
*@param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
*@param strResponse 输出参数,返回的内容
*@return 返回是否成功
*/
int Get(const std::string& strUrl,std::string& strResponse);
/**
*@brief HTTPS POST请求,无证书版本
*@param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
*@param strPost 输入参数,使用格式如下:para1=val1?2=val2
*@param strResponse 输出参数,返回的内容
*@param pCaPath 输入参数,为CA证书的路径,如果输入为NULL,则不验证服务器端证书的有效性
*@return 返回是否Posts成功
*/
int Posts(const std::string& strUrl,const std::string& strPost,std::string& strResponse,const char* pCaPath = NULL);
/**
*@brief HTTPS GET请求,无证书版
*@param strUrl 输入参数,请求的Url地址,如https://www.alipay.com
*@param strResponse 输出参数,返回的内容
*@param pCaPath 输入参数,为CA证书的路径,如果输入为NULL,则不验证服务端证书的有效性
*@return 返回是否Gets成功
*/
int Gets(const std::string& strUrl,std::string& strResponse,const char* pCaPath = NULL);
public:
void setDebug(bool bDebug);
private:
bool m_Debug;
};
CHttpCurl::CHttpCurl(void)
:m_Debug(false)
{
}
CHttpCurl::~CHttpCurl(void)
{
}
static int OnDebug(CURL *,curl_infotype itype,char* pData,size_t size,void *)
{
if(itype == CURLINFO_TEXT)
{
//printf("[TEXT]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_IN)
{
printf("[HEADER_IN]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_OUT)
{
printf("[HEADER_OUT]%s\n", pData);
}
else if(itype == CURLINFO_DATA_IN)
{
printf("[DATA_IN]%s\n", pData);
}
else if(itype == CURLINFO_DATA_OUT)
{
printf("[DATA_OUT]%s\n", pData);
}
return 0;
}
static size_t OnWirteData(void* buffer,size_t size,size_t nmemb,void* lpVoid)
{
std::string* str =dynamic_cast<std::string*>((std::string *) lpVoid);
if(NULL == str || NULL == buffer)
{
return -1;
}
char* pData = (char*)buffer;
str->append(pData,size* nmemb);
return nmemb;
}
int CHttpCurl::Post(const std::string &strUrl, const std::string &strPost, std::string &strResponse)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_Debug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE,1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL,strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWirteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20);//连接时间
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpCurl::PostFile(const std::string &strUrl, const std::string &strFileName, std::string &strResponse)
{
CURL *pCurl = NULL;
CURLcode res;
struct curl_slist *headerlist = NULL;
struct curl_httppost *post = NULL;
struct curl_httppost *last = NULL;
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "uploadfile",
CURLFORM_FILE, strFileName.c_str(),
//CURLFORM_CONTENTTYPE, "image/jpeg",
CURLFORM_END);
// curl_formadd(&post, &last,
// CURLFORM_COPYNAME, "body",
// CURLFORM_COPYCONTENTS, szJsonData,
// CURLFORM_END
// );
pCurl = curl_easy_init();
if (NULL != pCurl)
{
//curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 5);
curl_easy_setopt(pCurl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(pCurl, CURLOPT_HTTPPOST, post);
res = curl_easy_perform(pCurl);
if (res != CURLE_OK)
{
printf("curl_easy_perform() failed,error code is:%s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(pCurl);
}
return res;
}
int CHttpCurl::Get(const std::string &strUrl, std::string &strResponse)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_Debug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE,1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL,strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION,NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWirteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA,(void*)& strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT,20);
curl_easy_setopt(curl, CURLOPT_TIMEOUT,20);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed:%s\n",curl_easy_strerror(res));
}
curl_easy_perform(curl);
return res;
}
int CHttpCurl::Posts(const std::string &strUrl, const std::string &strPost, std::string &strResponse,const char* pCaPath)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_Debug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE,1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL,strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST,1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,strPost.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION,NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,OnWirteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA,(void*)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1);
if(NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}else{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,true);
curl_easy_setopt(curl, CURLOPT_CAINFO,pCaPath);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT,10);
curl_easy_setopt(curl, CURLOPT_TIMEOUT,10);
res = curl_easy_perform(curl);
curl_easy_perform(curl);
return res;
}
int CHttpCurl::Gets(const std::string &strUrl, std::string &strResponse,const char* pCaPath)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_Debug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE,1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL,strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION,NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,OnWirteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA,(void*)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1);
if(NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST,false);
}else{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,true);
curl_easy_setopt(curl, CURLOPT_CAINFO,pCaPath);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT,3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT,3);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
void CHttpCurl::setDebug(bool bDebug)
{
m_Debug = bDebug;
}
官网
参考: https://blog.csdn.net/u012234115/article/details/83869486