【问题标题】:Sending image from node.js server to ESP32 using ESP-IDF使用 ESP-IDF 从 node.js 服务器发送图像到 ESP32
【发布时间】:2021-04-19 09:22:04
【问题描述】:

我正在尝试使用 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 调用 esp_http_client_fetch_headers,而后者又从 lwip/src/api/sockets.c 调用 lwip_rec_tcp 函数。由于我已将缓冲区容量设置为 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-&gt;response-&gt;buffer 指针捕获所有数据块而不修改lwip_rec_tcp 以包括将数据上传到do ... while 循环内的spiffs 文件?

【问题讨论】:

  • @rustyx2:这就是服务器发送的内容。这不是客户端缓冲区接收的内容。这就是我希望客户端缓冲区显示的内容。在将缓冲区数据发送到客户端之前,服务器是否应该将其他内容作为标头的一部分发送?
  • 服务器当然不会发送十六进制的 PNG。它以原始二进制文件的形式发送。其中的代码只是将其显示为十六进制。大概原始二进制文件就是您所看到的,但由于您没有包含输出您收到的内容的代码,我们无法确定。
  • @romkey:更新问题以显示客户端缓冲区在从服务器接收数据之前和之后的样子
  • 您输出的是原始二进制文件而不将其转换为十六进制,所以它当然看起来像垃圾。如果您只是将原始字节转储到终端,图像文件看起来像垃圾。
  • @coder101 图片有多大? esp 上的可用内存大小通常不超过 200-300k。并且请检查您的malloc 调用是否返回0。最好使用new,因为您使用的是C++。我认为之前的 cmets 具有误导性。请像在服务器端一样将缓冲区打印为十六进制,然后您可以进行比较。如果您使用 printf 左右打印出二进制文件,它将停在任何可能只是图像一部分的 0 字节处。 ESP 上的程序输出也很好:)

标签: node.js c express buffer esp32


【解决方案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 示例。

【讨论】:

  • 谢谢。 esp_http_client_read_response() 在 while 循环中有效。由于 final amt ,最终缓冲区输出留下了先前 while 循环迭代的数据。来自服务器的数据小于 MAX_HTTP_OUTPUT_BUFFER。通过在服务器响应的末尾添加空字符“\0”(标记 C 中字符串的结尾)来解决此未决问题(对于那些遇到相同问题的人)来解决此问题。
  • 知道如何确保来自 esp_http_client_read_response 的缓冲区以字节数组形式读取从服务器发送的数据吗?我想将下载的数据保存到 spiffs 文件中,这样我就可以看到从服务器下载的图像。想法?
猜你喜欢
  • 1970-01-01
  • 2022-06-11
  • 2022-10-07
  • 2021-06-24
  • 2018-12-19
  • 1970-01-01
  • 1970-01-01
  • 2019-11-04
  • 1970-01-01
相关资源
最近更新 更多