使用 ESP-IDF

时间:2021-04-19 09:22:04

标签: node.js c express buffer esp32

我正在尝试使用 WIFI 和 ESP-IDF 将图像从 node.js 服务器发送到 ESP32 芯片。我相信这种传输是通过 TCP/IP 连接进行的。我可以使用 http get 请求或如下所示的 http_perform_as_stream_reader 函数发送常规文本数据。但是当涉及到从 node.js 服务器传输图像时,我无法这样做。我似乎在客户端收到垃圾。最终目标是将图像保存到 ESP32 上的 spiffs 文件中。这是我的代码:

服务器端:

const {imageprocess, convertToBase64} = require('../canvas');
const fs = require('fs');
const express = require('express');
const router = express.Router();
const path = require('path');

const imageFile = path.resolve(__dirname, "../images/file31.png")

router.get('/', funcAllStream)

module.exports = router;


function funcAllStream(req, res, next){
        newStream(res, imageFile)
}

function newStream(res, imageFile){
  var readStream = fs.createReadStream(imageFile);
  readStream.on('data', chunk => {
    res.send(chunk.toString('hex'));
  })
}

客户端(C++):

static void http_perform_as_stream_reader(void)
{
    char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
    esp_http_client_config_t config = {
        .url = "http://192.168.1.155:8085/api?file=image1.png"
    };
    esp_http_client_handle_t client = esp_http_client_init(&config); //calls esp_http_client_init from standard ESP32 component esp_http_client
    esp_err_t err;
    if ((err = esp_http_client_open(client, 0)) != ESP_OK) {
        return;
    }
    int content_length =  esp_http_client_fetch_headers(client); //calls esp_http_client_fetch_headers from standard ESP32 component esp_http_client
    int total_read_len = 0, read_len;
    if (total_read_len < content_length && content_length <= MAX_HTTP_RECV_BUFFER) {//MAX_HTTP_RECV_BUFFER defined to be larger than image1.png file on server side
        read_len = esp_http_client_read(client, buffer, content_length); //calls esp_http_client_read from standard ESP32 component esp_http_client
        if (read_len <= 0) {
            ESP_LOGE(TAG, "Error read data");
        }
        buffer[read_len] = 0;
    }
    esp_http_client_close(client);
    esp_http_client_cleanup(client);
    free(buffer);
}

http_perform_as_stream_reader();

在客户端,我确保缓冲区分配的空间大于图像文件大小。当我打印出客户端缓冲区中存储的内容时,我看到了绝对垃圾。服务器端发送如下所示的缓冲区流:

<Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 64 00 00 00 64 08 06 00 00 00 70 e2 95 54 00 00 00 06 62 4b 47 44 00 ff 00 ff 00 ff a0 bd a7 ...>

这是接收数据之前客户端缓冲区的样子:

���?Lv�~sN\
L��8J��s-�z���a�{�;�����\���~�Y���Di�2���]��|^,�x��N�݁�����`2g����n�w��b�Y�^���a���&��wtD�>n@�PQT�(�.z��(9,�?İ�

这是接收数据后客户端缓冲区的样子:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/octet-stream
Content-Length: 4517
ETag: W/"11a5-IhqwFPYLgC+NRfikTwS2exLtCWQ"
Date: Mon, 19 Apr 2021 16:15:48 GMT
Connection: keep-alive

�PNG

那么我如何确保客户端缓冲区实际上从服务器端以正确的格式接收到正确的数据呢?最终,我想将数据存储在客户端的 spiffs 文件中,并打开该文件以显示从 node.js 服务器传输的图像。

更新: 在服务器端将数据转换为十六进制格式后,我可以确认客户端收到正确的十六进制字符串。这是我在服务器端和客户端看到的:

89504e470d0a1a0a0000000d4948445200000064000000 ... 0fcc3c0ff03b8c85cc0643044ae0000000049454e44ae426082

开始和结束签名与 png 文件一致。

我已将客户端缓冲区设置为 10000(内容长度为 9037 字节)。尽管如此,我还是分两块收到了十六进制字符串。在我的客户端代码中,函数 http_perform_as_stream_reader 从 ESP 组件 esp_http_client_fetch_headers 调用 esp_http_client,后者又从 lwip_rec_tcp 调用 lwip/src/api/sockets.c 函数。由于我已将缓冲区容量设置为 10000(相当大的数量),esp_http_client_fetch_headers 会随标题一起获取相当大的十六进制字符串块。然后当 http_perform_as_stream_reader 函数调用 esp_http_client_read 函数时,它再次调用 lwip_rec_tcp 现在运行 do ... while 循环,直到它检索剩余的服务器端数据。由于 lwip_rec_tcp 将所有数据存储在缓冲区中,该缓冲区的存储容量较低(当然不能达到我在代码中为其设置的 10000),因此第一个数据块会被最后一个数据块覆盖。那么如何确保 client->response->buffer 指针捕获所有数据块而不修改 lwip_rec_tcp 以将数据上传到 do ... while 循环内的 spiffs 文件?

1 个答案:

答案 0 :(得分:1)

应用程序不应假设 esp_http_client_read 读取长度参数中指定的相同字节数。相反,应用程序应检查此 API 的返回值,该值指示相应调用读取的字节数。如果返回值为零,则表示读取了完整的数据。

要正常工作,应用程序应在 while 循环中调用 esp_http_client_read 并检查 esp_http_client_read 的返回值。

您也可以使用 esp_http_client_read_response,它是 esp_http_client_read 的辅助 API,用于内部处理 while 循环并一次性读取完整数据。

请参考使用 esp_http_client_read_response() API 的 http_native_request 示例。