//得到下载目标文件的大小的函数
long getDownloadFileLenth(const char *url)
{
long downloadFileLenth = 0;
CURL *handle = curl_easy_init();
curl\_easy\_setopt(handle, CURLOPT_URL, url);
curl\_easy\_setopt(handle, CURLOPT_HEADER, 1); //只需要header头
curl\_easy\_setopt(handle, CURLOPT_NOBODY, 1); //不需要body
if (curl\_easy\_perform(handle) == CURLE_OK) {
curl\_easy\_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);
} else {
downloadFileLenth = -1;
}
curl\_easy\_cleanup(handle);
return downloadFileLenth;
}
static size_t write_file(void *ptr, size_t size, size_t nmemb, void *stream)
{
return fwrite(ptr, size, nmemb, (FILE *)stream);
}
/**
函数功能:下载文件
入参:
出参:无
返回:成功0,失败-1
**/
int http_client_download_file(char *url, char *file, int timeOut_s)
{
int ret = -1;
FILE *fp = NULL;
CURL *curl = NULL;
CURLcode res = CURLE_OK;
curl = curl\_easy\_init(); // 初始化CURL
if (NULL == curl) {
goto done;
}
fp = fopen(file, "wb"); // 二进制写模式打开文件
if (fp == NULL) {
fprintf(stderr, "Cannot open file %s\n", file);
goto done;
}
// 设置libcurl选项
curl\_easy\_setopt(curl, CURLOPT_URL, url);// 设置下载URL
curl\_easy\_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); //设置连接超时,CURLOPT\_CONNECTTIMEOUT秒、CURLOPT\_CONNECTTIMEOUT\_MS 毫秒
curl\_easy\_setopt(curl, CURLOPT_TIMEOUT, timeOut_s);// 整个CURL 执行的时间, CURLOPT\_TIMEOUT秒、CURLOPT\_TIMEOUT\_MS毫秒
curl\_easy\_setopt(curl, CURLOPT_WRITEFUNCTION, write_file);// 设置写数据的函数
curl\_easy\_setopt(curl, CURLOPT_WRITEDATA, fp);// 设置写数据的文件指针
// SSL选项设置,如果是https的url则需要设置
curl\_easy\_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl\_easy\_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
res = curl\_easy\_perform(curl); // 执行下载
if (res != CURLE_OK) {
fprintf(stderr, "curl\_easy\_perform() failed: %s\n", curl\_easy\_strerror(res));
goto done;
}
ret = 0;
done:
if (fp) {
fclose(fp); // 关闭文件
if (0 > ret) {
remove(file);//失败则删除文件
}
}
if (curl) {
curl_easy_cleanup(curl); // 清理CURL
}
return ret;
}
void free_response(response_msg_t *response)
{
if (response->buf) {
free(response->buf);
response->buf = NULL;
}
}
static size_t write_buf(void *ptr, size_t size, size_t nmemb, void *userp)
{
response_msg_t *response = (response_msg_t *)userp;
size\_t n = size \* nmemb;
size\_t new_size = response->size + n;
char \*p = (char \*)realloc(response->buf, new_size + 1);
if (!p) {
/\* out of memory! \*/
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
response->buf = p;
memcpy(response->buf + response->size, ptr, n);
response->buf[new_size] = '\0';
response->size = new_size;
return n;
}
/**
函数功能:http客户端发送请求
入参:
url:URL的地址
method:method请求方式(“POST”、“GET”、“PUT”、“DELETE”)
body:正文,若无, 则填NULL
header:HTTP头
timeOut_s:请求超时时间(秒)
出参:response:响应返回的消息,需要手动释放空间,见free_response()
返回:成功返回0,失败-1
**/
int http_client_request(char *url, char *method, char *body, char *header, int timeOut_s, response_msg_t *response)
{
int ret = -1;
CURL *curl = NULL;
struct curl_slist *headers = NULL;
response->size = 0;
response->code = 0;
response->buf = (char \*)calloc(1, sizeof(char));
if (!response->buf) {
fprintf(stderr, "calloc failed\n");
goto done;
}
/\*
*在使用libcurl库函数之前,应该先调用一次curl_global_init()函数来初始化libcurl库,
*没有调用的话curl_easy_init()会自动调用。
*该函数并不是线程安全的,所以在多线程模式下最好放在主线程中调用一次。
*与curl_global_cleanup()配对使用。
*/
//curl_global_init(CURL_GLOBAL_ALL);
curl = curl\_easy\_init();
if (NULL == curl) {
goto done;
}
curl\_easy\_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); //设置连接超时,CURLOPT\_CONNECTTIMEOUT秒、CURLOPT\_CONNECTTIMEOUT\_MS 毫秒
curl\_easy\_setopt(curl, CURLOPT_TIMEOUT, timeOut_s); // 整个CURL 执行的时间, CURLOPT\_TIMEOUT秒、CURLOPT\_TIMEOUT\_MS毫秒
curl\_easy\_setopt(curl, CURLOPT_URL, url); //url地址
curl\_easy\_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);// 此选项设置为`1L`(或任何非零值)时,告诉libcurl在处理HTTP响应时遵循服务器返回的任何"Location:"头中定义的重定向
curl\_easy\_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");//用于设定一个默认协议,这个协议将在没有明确指定协议的情况下使用
if (0 == strncmp(url, "https://", 8)) {//SSL选项设置,如果是https的url则需要设置
#if 1
// 方法1, 设定为不验证证书和HOST
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#else
// 方法2, 设定一个SSL判别证书
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl,CURLOPT_CAINFO,“ca-cert.pem”); // TODO: 设置一个证书文件
#endif
}
curl\_easy\_setopt(curl, CURLOPT_CUSTOMREQUEST, method);//方法
if (body) {
curl\_easy\_setopt(curl, CURLOPT_POSTFIELDS, body);
curl\_easy\_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(body));
}
headers = curl\_slist\_append(headers, header);//设置头,根据实际修改
if (NULL == headers) {
goto done;
}
//headers = curl\_slist\_append(headers, "Expect:");//再加,防止Expect:
curl\_easy\_setopt(curl, CURLOPT_HTTPHEADER, headers);//添加协议头
/\* send all data to this function \*/
curl\_easy\_setopt(curl, CURLOPT_WRITEFUNCTION, write_buf);//设置写数据的函数
/\* we pass our 'chunk' struct to the callback function \*/
curl\_easy\_setopt(curl, CURLOPT_WRITEDATA, (void \*)response);//设置写数据的指针
//curl\_easy\_setopt(curl, CURLOPT\_VERBOSE, 0); // 是否打印调试信息,0不打印,1打印,不设置的话默认是0
//curl\_easy\_setopt(curl, CURLOPT\_HEADER, 0); // 是否输出响应头
if (CURLE_OK != curl\_easy\_perform(curl)) {
goto done;
}
//获取网络请求响应信息
curl\_easy\_getinfo(curl, CURLINFO_RESPONSE_CODE, &response->code);//状态码
if (200 != response->code) {//判断一下http的状态码是否对
goto done;
}
ret = 0;
done:
if (headers) {
curl_slist_free_all(headers);
headers = NULL;
}
if (curl) {
curl_easy_cleanup(curl);
curl = NULL;
}
//curl_global_cleanup();
return ret;
}
/**
函数功能:“表单方式”上传文件到服务器
入参:url:地址
method:method请求方式(“POST”、“GET”、“PUT”、“DELETE”)
header:HTTP头
timeOut_s:请求超时时间(秒)
copyName:上传文件的关键字段,对应file
file:为上传文件
n: 上传文件个数
出参:无
返回:成功返回0,失败-1
**/
int http_client_upload_files(char *url, char *method, char *header, int timeOut_s, char **copyName, char **file, int n)
{
int ret = -1;
int i = 0;
CURL \*curl = NULL;
curl = curl\_easy\_init();
if (curl) {
curl\_easy\_setopt(curl, CURLOPT_CUSTOMREQUEST, method);
curl\_easy\_setopt(curl, CURLOPT_URL, url);
curl\_easy\_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl\_easy\_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
curl\_easy\_setopt(curl, CURLOPT_TIMEOUT, timeOut_s);// 整个CURL 执行的时间, CURLOPT\_TIMEOUT秒, CURLOPT\_TIMEOUT\_MS毫秒
struct curl\_slist \*headers = NULL;
headers = curl\_slist\_append(headers, header);
curl\_easy\_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_mime \*mime = NULL;
curl_mimepart \*part = NULL;
mime = curl\_mime\_init(curl);
if (mime) {
for (i = 0; i < n; i++) {
part = curl\_mime\_addpart(mime);
curl\_mime\_name(part, copyName[i]);
curl\_mime\_filedata(part, file[i]);
}
curl\_easy\_setopt(curl, CURLOPT_MIMEPOST, mime);
if (CURLE_OK == curl\_easy\_perform(curl)) {
ret = 0;
}
}
if (mime) {
curl\_mime\_free(mime);
}
if (headers) {
curl\_slist\_free\_all (headers);
}
curl\_easy\_cleanup(curl);
}
return ret;
}
### 3. demo.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include “curl_http_client.h”
#include “curl.h”
#include <sys/stat.h>
int main(int argc, char *argv[])
{
int ret = 0;
char *method = (char *)“POST”;
char *url = (char *)“http://10.10.70.95:87/roadIn”;
char *body = (char *)“test test test!”;
char *header = CONTENT_TYPE_APP_JSON;
int timeOut_s = 4;
response\_msg\_t response = {0};
if (argc > 1) {
method = argv[1];
}
if (argc > 2) {
url = argv[2];
}
if (argc > 3) {
body = argv[3];
}
if (argc > 4) {
header = argv[4];
}
printf("you can input: ./xxx {method} {'url'} {'body'} {'header'}\n\n");
printf("method=%s\n", method);//请求的方法
printf("url=%s\n", url);//请求的地址
printf("body=%s\n", body);//请求的body正文
printf("header=%s\n", header);//请求的http头,比如Content-Type:application/json
printf("\n");
/\*
*在使用libcurl库函数之前,应该先调用一次curl_global_init()函数来初始化libcurl库,
*没有调用的话curl_easy_init()会自动调用。
*该函数并不是线程安全的,所以在多线程模式下最好放在主线程中调用一次。
*与curl_global_cleanup()配对使用。
*/
curl_global_init(CURL_GLOBAL_ALL);
/\*发送请求1\*/
ret = http\_client\_request(url, method, body, header, timeOut_s, &response);
if (0 == ret) {
printf("成功, code=%ld, size==%ld, buf=%s\n", response.code, response.size, response.buf);
} else {
printf("失败, code=%ld, size==%ld, buf=%s\n", response.code, response.size, response.buf);
}
#if 0 //返回内容保存到文件中
FILE *fp = fopen(“1.png”, “w”);
fwrite(response.buf, 1, response.size, fp);
fclose(fp);
#endif
free_response(&response);
/\*发送请求2\*/
//...
curl\_global\_cleanup();//与curl\_global\_cleanup()配对使用
return 0;
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!
[外链图片转存中…(img-QMtBQ9aH-1715797270798)]
[外链图片转存中…(img-X6CXFVQR-1715797270798)]
[外链图片转存中…(img-SYJbZIMp-1715797270799)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!