• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

"Вешается" ESP при частых запросах...

DrJarold

Member
Уважаемые ESPшнки, прошу вашей помощи... Есть код, который предназначен для обмена данными между ESP - Arduino по UART, в принципе все работает. Однако есть одно но... Если начать "флудить" запросами на адрес по которому работает ESP, то она зависает, т.е. в браузере идет загрузка и ничего не происходит пока не перезагрузишь ESP, так как все последующий запросы уже тоже не проходят. Однако если к примеру отключить Arduino и напрямую подключить ESP к Com порту, то уже "зафлудить" ее становиться тяжелее, но возможно, однако в этом случае если остановить загрузку то следующие запросы проходят нормально... Не могу понять почему это происходит!!!
Код:
#include <ESP8266WiFi.h>

byte ERROR_CONNECTION_TO_ACCESS_POINT = -2;
byte REQUEST_ERROR = -1;
byte REQUEST_GET_DEVICE = 0;
byte REQUEST_GET_CANAL_STATE = 1;
String ESP_REQUEST = "ESP_REQUEST_";
#define TIMEOUT 500
int waitCount = TIMEOUT;
const char* ssid = "";
const char* password = "";
WiFiServer server(80);
void setup() {
  Serial.begin(9600);
  Serial.println("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  server.begin();
  Serial.println(WiFi.localIP());
  Serial.flush();
}

void loop() {
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

  while (!client.available()) {
    delay(1);
  }

  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();

  // Match the request
  String val = ESP_REQUEST + REQUEST_ERROR;
  if (req.indexOf("/api/device") != -1)
    val = ESP_REQUEST + REQUEST_GET_DEVICE;
  else if (req.indexOf("/api/chanal") != -1)
    val = ESP_REQUEST + REQUEST_GET_CANAL_STATE;
  else {
    ReturnErrorResponse(client, "Error request URL");
    return;
  }

  Serial.println(val);
  Serial.flush();
  waitCount = TIMEOUT;
  while (Serial.available() <= 0) {
    waitCount--;
    if (waitCount <= 0) {

      ReturnErrorResponse(client, "Timeout");
      return;
    }
  }
  req = Serial.readStringUntil('\r\n');
  ReturnSuccessResponse(client, req);
}

void ReturnErrorResponse(WiFiClient client, String message) {
  String json = "{\"status\":\"error\",\"message\": " + message + ",\"data\":[]}";
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n " + json + "</html>\n";
  client.print(s);
  delay(1);

}

void ReturnSuccessResponse(WiFiClient client, String message) {
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n " + message + "</html>\n";
  client.print(s);
  delay(1);

}
Прошу прощения если задаю очевидные вопросы, которые уже обсуждались, не пинайте меня сильно я только учусь!!!!
 

Сергей_Ф

Moderator
Команда форума
@DrJarold в http у есп есть ошибки и такие атаки она не переваривает. По UDP такой проблемы нет, у меня переваривал более 30 сообщений в секунду и не вис.
 

DrJarold

Member
@Сергей_Ф т.е. вообще никак? По http? Мне бы просто добавить какое нибудь ограничение на запросы и не давать вешать устройство!
 

Сергей_Ф

Moderator
Команда форума
@Юрий Ботов э нет, корректно переваривать флуд и не виснуть, это явно на совести програмистов. С UDP ведь такого не случается. Я специально не тестировал, но 30-50 сообщений в сек по UDP перевариваются нормально, по http - дай Бог 0,5-1 в сек. Это явная ошибка. Естественно, речь не про ФЛУД.
 

Юрий Ботов

Moderator
Команда форума
С UDP ведь такого не случается.
Если у вас дома есть парочка компьютеров, попробуйте с одного (линкусового) на другой послать sudo ping -f адресвторого и посмотрите что будет. В винде такой пинг не будет работать.
Просто если вы подаете больше пакетов чем однопотоковая система успевает обработать за тот же период времени она ОБЯЗАТЕЛЬНО захлебнется. Выходов 2: от редких "выбросов" нагрузки спасает буферизация (но тогда нужно много памяти) или добавлять второй поток (процессор) чтобы прием и сортировка запросов и реальная обработка запросов выполнялась в разных потоках. И программист тут абсолютно не причем. Решения чисто хардверные.
 

Сергей_Ф

Moderator
Команда форума
@Юрий Ботов
попробовал на localhost и ничего криминального не обнаружил.
комп не завис, работал паралельно браузер, корректно прервалась работа по Ctrl+Break.
А ESP зависает и не отвисает после того как его перестали "бомбить" флудом.

Код:
sudo ping -f localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
^C
--- localhost ping statistics ---
142893 packets transmitted, 142893 received, 0% packet loss, time 12796ms
rtt min/avg/max/mdev = 0.008/0.009/0.439/0.005 ms, ipg/ewma 0.089/0.009 ms
Так же попробовал зафлудить свой смартфон на Андроид - результат такой же.
 

Юрий Ботов

Moderator
Команда форума
Ну с локалхостом не совсем корректно... когда начинает тормозить он и пинг генерирует медленнее, в результате все нормально. Попробую с другой стороны: вот процессор спокойно работает, а тут пришло прерывание от wifi, процессор начал отрабатывать прерывание, не успел, а тут еще одно прерывание (я немного утрирую и описываю упрощенно), переменные старого прерывания остаются в стэке, создаются переменные нового прерывания обрабатывается прерывание... опять новое прерывание, переменные второго прерывания в стэке, создаются переменные 3-го кладутся в стэк и так далее... стэк растет...растет...растет и буквально через десяток таких вложенных прерываний он вторгается в область данных и крушит там все подряд (это не интерпретатор, он выход за границы не проверяет), потом еще через пару десятков вложенных прерываний стэк начинает крушить область программы (да! программа в esp тоже в ОЗУ). После этого... можно сколько угодно выключать внешний флуд. Программы то уже НЕТ.
 

Сергей_Ф

Moderator
Команда форума
@Юрий Ботов проверил флуд пинга на ESP - пакеты теряются, но ESP не вешается. И даже спокойно отрабатывает запросы HTTP, так что думаю Вы не правы и прграмисты что то напортачили именно с HTTP.
 

Юрий Ботов

Moderator
Команда форума
Просто обработка HTTPзанимает значительно больше команд (времени) чем простой ответ на Ping. Ну как скажете...
 

nikolz

Well-known member
Да действительно UDP решает проблему, спасибо.
ESP по TCP может работать с одним открытым соединением и до 2-х еще в очереди. Эта проблема известна давно.
Поэтому давно рекомендую UDP.
Но некоторые, особо умные, все продолжают эксперименты с линуксом и дают бестолковые советы.
 
Сверху Снизу