【ESP32】ESP32实现的C语言post发送图片到服务端

ESP32实现的C语言post发送图片到服务端
一、需求
  1. 需求是这种,需要将ESP实时拍照的项目修改,原有的项目是通过在esp项目上搭建了一个webhttpserver,然后通过这个server搭建起来之后
  2. 在运行之后,server会产生一个http的访问地址,这个地址可以通过浏览器访问,访问之后,后面会在浏览器中产生一个图片。
  3. 现在按照修改的方式是,将产生的图片post按照一定的时间间隔post到服务端,这个环境是C语言,所以就有使用C语言来实现post请求,post的请求内容是这个图片
二、实现
  1. 照相的项目是在github上找到的,项目地址,原本想使用MQTT来实现这个,已经看到了有实现的方案,但是MQTT在ESP32上面有字节限制,传不了比较大的图片。
  2. 使用post参考了,基于C语言实现HTTP POST 表单形式上传文件
  3. 服务端使用的是springboot临时搭建了一个demo,先使用的是网页传的一个图片到服务端测试了一下,然后再用了一个这个自动上传,出现了EOF错误,是因为write的时候,大小使用的是strlen方式进行的上传。
  4. 将strlen修改为字节的本来的大小,就可以上传图片了。
  5. 只是将代码的主要的部分列出来了,但是没有接收服务端返回的消息
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);
    }
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值