无法使用 SIM800L+ESP32 发送大小大于 1449 个字符的 HTTP POST 负载
Unable to send HTTP POST payload of size greater than 1449 characters with SIM800L+ESP32
所以我在我的 ESP32+SIM800L 设置上通过 HTTP POST 将数据发送到我的 php 托管在 000WebHost 上的脚本。
我正在以 800Hz 的频率记录传感器数据并将其存储在一个字符数组中,例如:a[]=3&a[]=5&a[]=8... 它成为 POST 请求的有效负载数组。
出于某种原因,我只能发送 161 个值,内容长度大约为 1449。
代码有点长所以我在这里减少了它:
我正在使用 TinyGSM 库
//Start GSM:
SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
SerialMon.println("Initializing modem...");
modem.init();
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
if (modem.isGprsConnected()) {
SerialMon.println("GPRS connected");
}
SerialMon.print("Connecting to ");
SerialMon.println(server);
if (!client.connect(server, port)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
// Record Sensor values for one second
//Send the character array to the httpPost function:
if (client.connect(server,port)) {
Serial.println("connected");
client.println("POST /upload.php? HTTP/1.1");
client.println("Host: epiblastic-reactor.000webhostapp.com");
client.println("User-Agent: TTGO-TCALL/1.0");
client.println("Content-Type: application/x-www-form-urlencoded;");
client.print("Content-Length: ");
client.println(String(acceldata).length());
client.println();
client.println(acceldata);
uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) {
// Print available data
while (client.available()) {
char c = client.read();
SerialMon.print(c);
timeout = millis();
}
如果我发送超过 161 个值,串行监视器打印:
#Available: 0 on 1
不断。
出了什么问题?
有人可以帮我吗?
没有什么明显的,您可能想检查您的 TinyGSM 配置并可能启用该库的调试输出。
无论如何。总有一些常见的嫌疑人:
首先,您没有在 ESP32 和调制解调器之间的串口 link 上使用流量控制。这意味着如果您向调制解调器发送更多数据以使其可以发送到 Internet,调制解调器的串行缓冲区可能会溢出。好的解决方案是在两侧启用串行流控制(硬件最好,软件可以)。一个糟糕的解决方案是更慢地发送数据,例如每隔几秒 1400 字节。
其次检查服务器端是否发生任何异常,即服务器关闭连接。
然后你可以检查 - 无论对象 client
是什么(你的代码没有显示它的创建位置) - 它实际上允许你使用大量数据调用 println()
。
至于您的数据量,通过 HTTP 请求发送 6-7 KiB 的数据并没有什么异常。仅当您希望通过吞吐量较小的 link 每秒发送那么多时才会出现问题 - 显然它没有能力做到这一点。 GPRS 上传速度慢。
以太网的MTU通常为1500,但对于SIM800,我认为它设置为1460字节(您可以使用AT+CIPSEND?
查看该值)。 TinyGSM 使用的 TCP/HTTP 客户端似乎不会将超过一个 MTU 的数据分成块,因此用户有责任这样做。
这里是一个关于如何在多个块中发送数据的例子。
代码已从初始输入更新
#define ONE_CHUNK 1024 //you can change it as long as it is <= MTU
int payload_length = acceldata.length(); //assuming your data is already a String object
client.print("Content-Length: ");
client.println(payload_length);
client.println();
if (payload_length < ONE_CHUNK) { //less than ONE_CHUNK, send it
client.println(acceldata);
}
else { // more than ONE_CHUNK, break it into number of chunks
int chunks = payload_length / ONE_CHUNK;
for(int i = 0; i < chunks; i++){
client.print(acceldata.substring(i*ONE_CHUNK, (i*ONE_CHUNK)+ONE_CHUNK));
}
int last_chunk = payload_length - chunks * ONE_CHUNK;
if (last_chunk) {
client.println(acceldata.substring(payload_length-last_chunk, payload_length - 1));
}
}
所以我在我的 ESP32+SIM800L 设置上通过 HTTP POST 将数据发送到我的 php 托管在 000WebHost 上的脚本。 我正在以 800Hz 的频率记录传感器数据并将其存储在一个字符数组中,例如:a[]=3&a[]=5&a[]=8... 它成为 POST 请求的有效负载数组。
出于某种原因,我只能发送 161 个值,内容长度大约为 1449。
代码有点长所以我在这里减少了它: 我正在使用 TinyGSM 库
//Start GSM:
SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
SerialMon.println("Initializing modem...");
modem.init();
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
if (modem.isGprsConnected()) {
SerialMon.println("GPRS connected");
}
SerialMon.print("Connecting to ");
SerialMon.println(server);
if (!client.connect(server, port)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
// Record Sensor values for one second
//Send the character array to the httpPost function:
if (client.connect(server,port)) {
Serial.println("connected");
client.println("POST /upload.php? HTTP/1.1");
client.println("Host: epiblastic-reactor.000webhostapp.com");
client.println("User-Agent: TTGO-TCALL/1.0");
client.println("Content-Type: application/x-www-form-urlencoded;");
client.print("Content-Length: ");
client.println(String(acceldata).length());
client.println();
client.println(acceldata);
uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) {
// Print available data
while (client.available()) {
char c = client.read();
SerialMon.print(c);
timeout = millis();
}
如果我发送超过 161 个值,串行监视器打印:
#Available: 0 on 1
不断。
出了什么问题? 有人可以帮我吗?
没有什么明显的,您可能想检查您的 TinyGSM 配置并可能启用该库的调试输出。
无论如何。总有一些常见的嫌疑人:
首先,您没有在 ESP32 和调制解调器之间的串口 link 上使用流量控制。这意味着如果您向调制解调器发送更多数据以使其可以发送到 Internet,调制解调器的串行缓冲区可能会溢出。好的解决方案是在两侧启用串行流控制(硬件最好,软件可以)。一个糟糕的解决方案是更慢地发送数据,例如每隔几秒 1400 字节。
其次检查服务器端是否发生任何异常,即服务器关闭连接。
然后你可以检查 - 无论对象 client
是什么(你的代码没有显示它的创建位置) - 它实际上允许你使用大量数据调用 println()
。
至于您的数据量,通过 HTTP 请求发送 6-7 KiB 的数据并没有什么异常。仅当您希望通过吞吐量较小的 link 每秒发送那么多时才会出现问题 - 显然它没有能力做到这一点。 GPRS 上传速度慢。
以太网的MTU通常为1500,但对于SIM800,我认为它设置为1460字节(您可以使用AT+CIPSEND?
查看该值)。 TinyGSM 使用的 TCP/HTTP 客户端似乎不会将超过一个 MTU 的数据分成块,因此用户有责任这样做。
这里是一个关于如何在多个块中发送数据的例子。
代码已从初始输入更新
#define ONE_CHUNK 1024 //you can change it as long as it is <= MTU
int payload_length = acceldata.length(); //assuming your data is already a String object
client.print("Content-Length: ");
client.println(payload_length);
client.println();
if (payload_length < ONE_CHUNK) { //less than ONE_CHUNK, send it
client.println(acceldata);
}
else { // more than ONE_CHUNK, break it into number of chunks
int chunks = payload_length / ONE_CHUNK;
for(int i = 0; i < chunks; i++){
client.print(acceldata.substring(i*ONE_CHUNK, (i*ONE_CHUNK)+ONE_CHUNK));
}
int last_chunk = payload_length - chunks * ONE_CHUNK;
if (last_chunk) {
client.println(acceldata.substring(payload_length-last_chunk, payload_length - 1));
}
}