网络编程之http客户端(基于libcurl发送POST、GET

//得到下载目标文件的大小的函数
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年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

[外链图片转存中…(img-QMtBQ9aH-1715797270798)]

[外链图片转存中…(img-X6CXFVQR-1715797270798)]

[外链图片转存中…(img-SYJbZIMp-1715797270799)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值