从 Arduino 代码中将 HTML 用作 C 数组 - 字符串大小限制问题
Serving HTML as C array from Arduino code - String size limit problem
我一直在 Wiznet W5100S-EVB-Pico 上开发 HTML / websocket 服务器,在 Arduino IDE 中编程。到目前为止一切正常,但我 运行 我认为是字符串大小限制。我想这是代码处理 const char 的方式,但我不知道如何正确处理。
希望有人愿意帮忙:)
让我解释一下:
- 我将 index.html 转换为包含 const char 数组的 index_html.h 文件:
const char c_index_html[] = {
0x3c,0x21,0x44,0x4f,0x43,..., ..., 0x6d,0x6c,0x3e};
- 在我的代码中包含 index_html.h 文件:
#include "index_html.h"
现在实际服务于“HTML”的代码
if (web_client){
Serial.println("New client");
// an http request ends with a blank line
bool currentLineIsBlank = true;
while (web_client.connected()){
if (web_client.available()){
char c = web_client.read();
if (c == '\n' && currentLineIsBlank) // if you've gotten to the end of the line (received a newline
{ // character) and the line is blank, the http request has ended,
Serial.println(F("Sending response")); // so you can send a reply
String strData;
strData = c_index_html;
web_client.println(strData);
break;
}
if (c == '\n')
{
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r')
{
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
这不是最漂亮的代码,它是从示例中拼凑而成的,现在罪魁祸首似乎是:
String strData;
strData = c_index_html;
web_client.println(strData);
当我向 HTML 添加额外的代码并查看页面源代码时,代码不完整。我测试了将 HTML 减少到最小值并解决了问题。
所以我的主要问题是:
- 如何在不使用 'String' 的情况下提供 'const char c_index_html'?
还有:
- 如何美化整个 'if (web_client)' 服务功能?
非常感谢您一路走来 post 如果您有任何建议,我将不胜感激 ;)
编辑: There is a bug in the ethernet library shown in this post.
不知道对你有没有影响;你应该看看你的库实现。
我假设 web_client
是 Arduino 库中 EthernetClient 的一个实例。
EthernetClient::println
继承自Print
via Stream
,定义为write
,即:
size_t EthernetClient::write(const uint8_t *buf, size_t size)
{
if (_sockindex >= MAX_SOCK_NUM) return 0;
// This library code is not correct:
if (Ethernet.socketSend(_sockindex, buf, size)) return size;
setWriteError();
return 0;
}
所以我们看到它要求套接字将缓冲区发送到某个大小。 套接字可以响应大小或 0(参见编辑);如果它以 0 响应,则有一个错误条件需要检查。
编辑: 它应该是这样工作的。由于 write
总是返回请求的大小而不告诉您写入了多少,因此您无法使用 print
/write
工具解决问题,需要直接使用 socketSend
.
您没有检查此写入的结果(应该通过 println
),因此您不知道套接字是否发送了 size
字节、0 字节或一些之间的数字。
在 EthernetClient::connect
中我们看到它正在打开一个 TCP 流:
_sockindex = Ethernet.socketBegin(SnMR::TCP, 0);
当您调用 socketSend
时,您实际上只是将缓冲区复制到网络堆栈中的缓冲区中。 TCP 驱动程序会尽可能地写出该缓冲区。如果您写入该缓冲区的速度快于它被刷新到网络的速度,那么您将填满它并且您的 socketSend
调用将开始返回 < size
字节。参见 Does send() always send whole buffer?。
所以您可能是对的,您的字符串太长了。你需要做的是分散你的写作。网络上有无数教程介绍了这一点;在你的例子中大致是这样的:
...
size_t bytesRemaining = 0;
while (web_client.connected()){
if (bytesRemaining > 0) {
// Still responding to the last request
char const* const cursor = c_index_html
+ sizeof(c_index_html)
- bytesRemaining;
size_t const bytesWritten = web_client.write(cursor, bytesRemaining);
if (!bytesWritten) {
// check for error
}
bytesRemaining -= bytesWritten;
if (bytesRemaining == 0) {
// End the message. This might not write!
// We should add the '\n' to the source array so
// it's included in our write-until-finished routine.
web_client.println();
// Stop listening
break;
}
} else if (web_client.available()){
// Time for a new request
char c = web_client.read();
if (c == '\n' && currentLineIsBlank)
{
Serial.println(F("Sending response"));
// Start responding to this request
bytesRemaining = sizeof(c_index_html);
continue;
}
...
这就是我的想法。我不是专家所以我可能是错的,但它似乎是有道理的。
这不是“解决方案”中的答案,但我发现使用 W5100S 有 2k 缓冲区大小限制-EVB-Pico。事实上,如果我将 HTML 保持在 2k 以下,它就可以工作。事实证明,我实际上得到了 Matt Murphy 的建议,但 2k 限制是问题所在。看起来像是 hardware/library 的限制,对此不是很确定。
现在我会把我的 HTML 和 Javascript 缩小到最小,并用例如 textfixer.com 进一步压缩它。我想我可能会写一些 python 代码来做到这一点
也许下面的 link 中有解决方案,但目前我会尝试接受这些限制
Link:
https://github.com/khoih-prog/EthernetWebServer/issues/7
我一直在 Wiznet W5100S-EVB-Pico 上开发 HTML / websocket 服务器,在 Arduino IDE 中编程。到目前为止一切正常,但我 运行 我认为是字符串大小限制。我想这是代码处理 const char 的方式,但我不知道如何正确处理。
希望有人愿意帮忙:)
让我解释一下:
- 我将 index.html 转换为包含 const char 数组的 index_html.h 文件:
const char c_index_html[] = {
0x3c,0x21,0x44,0x4f,0x43,..., ..., 0x6d,0x6c,0x3e};
- 在我的代码中包含 index_html.h 文件:
#include "index_html.h"
现在实际服务于“HTML”的代码
if (web_client){
Serial.println("New client");
// an http request ends with a blank line
bool currentLineIsBlank = true;
while (web_client.connected()){
if (web_client.available()){
char c = web_client.read();
if (c == '\n' && currentLineIsBlank) // if you've gotten to the end of the line (received a newline
{ // character) and the line is blank, the http request has ended,
Serial.println(F("Sending response")); // so you can send a reply
String strData;
strData = c_index_html;
web_client.println(strData);
break;
}
if (c == '\n')
{
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r')
{
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
这不是最漂亮的代码,它是从示例中拼凑而成的,现在罪魁祸首似乎是:
String strData;
strData = c_index_html;
web_client.println(strData);
当我向 HTML 添加额外的代码并查看页面源代码时,代码不完整。我测试了将 HTML 减少到最小值并解决了问题。
所以我的主要问题是:
- 如何在不使用 'String' 的情况下提供 'const char c_index_html'?
还有:
- 如何美化整个 'if (web_client)' 服务功能?
非常感谢您一路走来 post 如果您有任何建议,我将不胜感激 ;)
编辑: There is a bug in the ethernet library shown in this post.
不知道对你有没有影响;你应该看看你的库实现。
我假设 web_client
是 Arduino 库中 EthernetClient 的一个实例。
EthernetClient::println
继承自Print
via Stream
,定义为write
,即:
size_t EthernetClient::write(const uint8_t *buf, size_t size)
{
if (_sockindex >= MAX_SOCK_NUM) return 0;
// This library code is not correct:
if (Ethernet.socketSend(_sockindex, buf, size)) return size;
setWriteError();
return 0;
}
所以我们看到它要求套接字将缓冲区发送到某个大小。 套接字可以响应大小或 0(参见编辑);如果它以 0 响应,则有一个错误条件需要检查。
编辑: 它应该是这样工作的。由于 write
总是返回请求的大小而不告诉您写入了多少,因此您无法使用 print
/write
工具解决问题,需要直接使用 socketSend
.
您没有检查此写入的结果(应该通过 println
),因此您不知道套接字是否发送了 size
字节、0 字节或一些之间的数字。
在 EthernetClient::connect
中我们看到它正在打开一个 TCP 流:
_sockindex = Ethernet.socketBegin(SnMR::TCP, 0);
当您调用 socketSend
时,您实际上只是将缓冲区复制到网络堆栈中的缓冲区中。 TCP 驱动程序会尽可能地写出该缓冲区。如果您写入该缓冲区的速度快于它被刷新到网络的速度,那么您将填满它并且您的 socketSend
调用将开始返回 < size
字节。参见 Does send() always send whole buffer?。
所以您可能是对的,您的字符串太长了。你需要做的是分散你的写作。网络上有无数教程介绍了这一点;在你的例子中大致是这样的:
...
size_t bytesRemaining = 0;
while (web_client.connected()){
if (bytesRemaining > 0) {
// Still responding to the last request
char const* const cursor = c_index_html
+ sizeof(c_index_html)
- bytesRemaining;
size_t const bytesWritten = web_client.write(cursor, bytesRemaining);
if (!bytesWritten) {
// check for error
}
bytesRemaining -= bytesWritten;
if (bytesRemaining == 0) {
// End the message. This might not write!
// We should add the '\n' to the source array so
// it's included in our write-until-finished routine.
web_client.println();
// Stop listening
break;
}
} else if (web_client.available()){
// Time for a new request
char c = web_client.read();
if (c == '\n' && currentLineIsBlank)
{
Serial.println(F("Sending response"));
// Start responding to this request
bytesRemaining = sizeof(c_index_html);
continue;
}
...
这就是我的想法。我不是专家所以我可能是错的,但它似乎是有道理的。
这不是“解决方案”中的答案,但我发现使用 W5100S 有 2k 缓冲区大小限制-EVB-Pico。事实上,如果我将 HTML 保持在 2k 以下,它就可以工作。事实证明,我实际上得到了 Matt Murphy 的建议,但 2k 限制是问题所在。看起来像是 hardware/library 的限制,对此不是很确定。
现在我会把我的 HTML 和 Javascript 缩小到最小,并用例如 textfixer.com 进一步压缩它。我想我可能会写一些 python 代码来做到这一点
也许下面的 link 中有解决方案,但目前我会尝试接受这些限制
Link: https://github.com/khoih-prog/EthernetWebServer/issues/7