NodeMcu 使用 WiFiClientSecure readStringUntil() 需要 15 秒才能完成
NodeMcu using WiFiClientSecure readStringUntil() taking 15 seconds to complete
我有以下代码:
if (net.connect(host, port)) {
String req = "GET /curTemp?temp=" + String(temperatureFahrenheit) + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Authorization: Basic xxxxxxxxxxxxxxxxx\r\n" +
"Connection: close\r\n\r\n";
net.print(req);
// Get headers
while (net.connected()) {
String line = net.readStringUntil('\r');
if (line == "\r") {
break;
}
}
// Get temperature
StaticJsonBuffer<50> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(net.readStringUntil('\r'));
const char* temp = root["temp"];
Serial.print("Temp:");
Serial.println(temp);
} else {
Serial.println("connection failed");
}
这需要 15 秒才能完成,我不确定为什么。我可以在 Web 浏览器中使用相同的请求,它会立即返回。特别是 net.readStringUntil 似乎在花时间。
更新:我通过设置 setTimeout(1000) 找到了解决方法,但我不明白为什么这是必要的。请求不应该关闭连接并在完成时终止 readStringUntil() 吗?可能我不明白WiFiClientSecure?
更新 2:我发现了问题。请参阅下面的答案。
好的,我将其放入以进行澄清。每个示例都为 readStringUntil() 显示“\r”,这可能会造成混淆。所以如果你使用 '\r' 那么下一次读取将以 '\n' 开头,所以如果你正在寻找 headers 的结尾,它实际上是 '\n\r\n' 因为从先前读取的行结转。那么会发生什么情况是您的数据与 crlfs 不同步。我发现使用“\n”作为终止符效果更好,因为 headers 的标准格式以“\r\n”结尾。然后,您可以通过仅查找 '\r'(\n 终止符被 readStringUntil() 吃掉)来测试 headers 的结尾。然后你可以开始另一个循环来获取你的数据。然后一切正常,不需要 setTimeout。
示例:
if (net.connect(host, port)) {
String req = "GET /curTemp?temp=" + String(temperatureFahrenheit) + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Authorization: Basic dXNlcjpkYWYxMjM0\r\n" +
"Connection: close\r\n\r\n";
net.print(req);
delay(1000);
// Get headers
while (net.available()) {
// Note \n for terminator
String line = net.readStringUntil('\n');
// Only \r because \n is eaten by readStringUntil()
if (line == "\r") {
break;
}
}
// Now look for data (in my case only one line of JSON)
// No \r\n on this one.
String line = net.readStringUntil('}');
// Put back the character eaten by readStringUntil()
line = line + "}";
Serial.println(line);
我有以下代码:
if (net.connect(host, port)) {
String req = "GET /curTemp?temp=" + String(temperatureFahrenheit) + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Authorization: Basic xxxxxxxxxxxxxxxxx\r\n" +
"Connection: close\r\n\r\n";
net.print(req);
// Get headers
while (net.connected()) {
String line = net.readStringUntil('\r');
if (line == "\r") {
break;
}
}
// Get temperature
StaticJsonBuffer<50> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(net.readStringUntil('\r'));
const char* temp = root["temp"];
Serial.print("Temp:");
Serial.println(temp);
} else {
Serial.println("connection failed");
}
这需要 15 秒才能完成,我不确定为什么。我可以在 Web 浏览器中使用相同的请求,它会立即返回。特别是 net.readStringUntil 似乎在花时间。
更新:我通过设置 setTimeout(1000) 找到了解决方法,但我不明白为什么这是必要的。请求不应该关闭连接并在完成时终止 readStringUntil() 吗?可能我不明白WiFiClientSecure?
更新 2:我发现了问题。请参阅下面的答案。
好的,我将其放入以进行澄清。每个示例都为 readStringUntil() 显示“\r”,这可能会造成混淆。所以如果你使用 '\r' 那么下一次读取将以 '\n' 开头,所以如果你正在寻找 headers 的结尾,它实际上是 '\n\r\n' 因为从先前读取的行结转。那么会发生什么情况是您的数据与 crlfs 不同步。我发现使用“\n”作为终止符效果更好,因为 headers 的标准格式以“\r\n”结尾。然后,您可以通过仅查找 '\r'(\n 终止符被 readStringUntil() 吃掉)来测试 headers 的结尾。然后你可以开始另一个循环来获取你的数据。然后一切正常,不需要 setTimeout。
示例:
if (net.connect(host, port)) {
String req = "GET /curTemp?temp=" + String(temperatureFahrenheit) + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Authorization: Basic dXNlcjpkYWYxMjM0\r\n" +
"Connection: close\r\n\r\n";
net.print(req);
delay(1000);
// Get headers
while (net.available()) {
// Note \n for terminator
String line = net.readStringUntil('\n');
// Only \r because \n is eaten by readStringUntil()
if (line == "\r") {
break;
}
}
// Now look for data (in my case only one line of JSON)
// No \r\n on this one.
String line = net.readStringUntil('}');
// Put back the character eaten by readStringUntil()
line = line + "}";
Serial.println(line);