ESP32实现的C语言post发送图片到服务端
一、需求
- 需求是这种,需要将ESP实时拍照的项目修改,原有的项目是通过在esp项目上搭建了一个webhttpserver,然后通过这个server搭建起来之后
- 在运行之后,server会产生一个http的访问地址,这个地址可以通过浏览器访问,访问之后,后面会在浏览器中产生一个图片。
- 现在按照修改的方式是,将产生的图片post按照一定的时间间隔post到服务端,这个环境是C语言,所以就有使用C语言来实现post请求,post的请求内容是这个图片
二、实现
- 照相的项目是在github上找到的,项目地址,原本想使用MQTT来实现这个,已经看到了有实现的方案,但是MQTT在ESP32上面有字节限制,传不了比较大的图片。
- 使用post参考了,基于C语言实现HTTP POST 表单形式上传文件
- 服务端使用的是springboot临时搭建了一个demo,先使用的是网页传的一个图片到服务端测试了一下,然后再用了一个这个自动上传,出现了EOF错误,是因为write的时候,大小使用的是strlen方式进行的上传。
- 将strlen修改为字节的本来的大小,就可以上传图片了。
- 只是将代码的主要的部分列出来了,但是没有接收服务端返回的消息
static void sendHttpRequest() {
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
struct in_addr *addr;
int s, r;
// char recv_buf[1024];
// char mid_buf[1024];
// char* mid_buf = (char *)malloc(fb_data.size);
printf("==== start DNS域名解析 =====\n");
// 1. DNS域名解析
int error = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
if(error != 0 || res == NULL)
{
ESP_LOGE(TAG, "DNS lookup failed error=%d res=%p\r\n", error, res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
return;
}
printf("==== start 打印获取的IP =====\n");
// 2. 打印获取的IP
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
// ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr));
printf("==== start 新建socket =====\n");
// 3. 新建socket
s = socket(res->ai_family, res->ai_socktype, 0);
if(s < 0)
{
ESP_LOGE(TAG, "... Failed to allocate socket.\r\n");
close(s);
freeaddrinfo(res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
return;
}
printf("==== start 连接ip =====\n");
// 4. 连接ip
if(connect(s, res->ai_addr, res->ai_addrlen) != 0)
{
ESP_LOGE(TAG, "... socket connect failed errno=%d\r\n", errno);
close(s);
freeaddrinfo(res);
vTaskDelay(4000 / portTICK_PERIOD_MS);
return;
}
freeaddrinfo(res);
// ==== 开始拼接字符串 ====
// 0. 添加变量
buffer_t fb_data = {
.data = camera_get_fb(),
.size = camera_get_data_size()
};
char* requestHead = (char*)malloc(1024); // 这个是请求头
memset(requestHead, 0, 1024);
char* requestInfo = (char*)malloc(1024); // 这个是请求类型
memset(requestInfo, 0, 1024);
char* requestEnd = (char*)malloc(1024); // 这个是请求尾
memset(requestEnd, 0, 1024);
char* httpBoundary = (char*)malloc(64);
memset(httpBoundary, 0, 64);
long long int timestamp;
struct timeval tv;
gettimeofday(&tv,NULL);
timestamp = (long long int)tv.tv_sec * 1000 + tv.tv_usec;
snprintf(httpBoundary, 64, "---------------------------%lld", timestamp);
unsigned long totalsize = 0;
unsigned long filesize = fb_data.size;
printf("==== start strcat head =====\n");
// 1. 拼接请求中间部分
unsigned long infoLen = sprintf(requestInfo,UPLOAD_REQUEST, httpBoundary, "myphoto.jpg");
printf("==== infoLen: %d=====\n", (int)infoLen);
// 2. 结束信息
unsigned long endLen = sprintf(requestEnd, "\r\n--%s--\r\n", httpBoundary);
printf("==== endLen: %d=====\n", (int)endLen);
// 3. 计算请求体总大小
totalsize = filesize + infoLen + endLen;
printf("==== totalsize: %d=====\n", (int)totalsize);
// 4. 添加请求头,请求头需要上面的请求体计算之后才能添加
unsigned long headLen = sprintf(requestHead, HTTP_HEAD, httpBoundary, totalsize);
printf("==== headLen: %d=====\n", (int)headLen);
// 5. 计算总大小
totalsize += headLen;
printf("==== totalsize: %d=====\n", (int)totalsize);
// 6. 申请发送消息的内存
char* requestStr = (char*)malloc(totalsize);
if (requestStr == NULL){
printf("malloc request fail !\r\n");
return -1;
}
memset(requestStr, 0, totalsize);
// 7. 拼接http字节流信息
strcat(requestStr, requestHead); //http头信息
strcat(requestStr, requestInfo);
memcpy(requestStr + headLen + infoLen, fb_data.data, filesize);
memcpy(requestStr + headLen + infoLen + filesize, requestEnd, endLen);
puts(requestStr);
printf("==== start 发送http包 =====\n");
// 8. 发送http包
if (write(s, requestStr, totalsize) < 0)
{
ESP_LOGE(TAG, "... socket send failed\r\n");
close(s);
vTaskDelay(4000 / portTICK_PERIOD_MS);
return;
}
printf("==== start 清缓存 =====\n");
// // 6. 清缓存
// memset(mid_buf,0, 1024);
// printf("==== start 获取http应答包 =====\n");
// 7. 获取http应答包
// do {
// bzero(recv_buf, sizeof(recv_buf));
// r = read(s, recv_buf, sizeof(recv_buf)-1);
// strcat(mid_buf,recv_buf);
// } while(r > 0);
vTaskDelay(4000 / portTICK_PERIOD_MS);
//json解析
// cjson_to_struct_info(mid_buf);
//关闭socket,http是短连接
close(s);
free(requestHead);
free(requestInfo);
free(requestEnd);
free(httpBoundary);
free(requestStr);
//延时一会
for(int countdown = 10; countdown >= 0; countdown--) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}