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

Некорректная отработка TCP Retransmission

Клон WeMos D1 mini, среди прочего отрабатывает код простого http сервера на ESP8266WebServer.

К нему обращается питоновский код с другого компа на линуксе, запросом GET.

Такое впечатление что на TCP пакет с запросом модуль не успевает ответить за время TCP_RTO_MIN (200 ms), и линукс шлет retransmission пакет.
Проблема в том, что модуль хоть и ACK оба пакета с запросом быстренько, но потом как-бы подвисает на 5секунд, и основной контент возвращает уже с задержкой.
При этом если тот же GET запрос делать через curl, который не вызывает retransmission (почему не знаю) то ответ модуля всегда приходит быстро, без задержек.
5 секунд это, насколько я понимаю, какой-то таймаут у TCP стека ESP8266.
Мне кажется что получение retransmission пакета запроса вводит TCP стек ESP8266 в ступор.

Нет ли у кого-то понимания, что там происходит и как бороться?
Прикладываю скриншот wiresharkesp8266-tcp-retr-issue.png

PS Какая там прошивка не знаю и как посмотреть не знаю. Программирую D1 mini через Ардуино ИДЕ.
 

pvvx

Активный участник сообщества
У вас вообще полная белиберда от ESP - на закрытие соединения он дает RST :) :)
Такое впечатление что на TCP пакет с запросом модуль не успевает ответить за время TCP_RTO_MIN (200 ms), и линукс шлет retransmission пакет.
Проблема в том, что модуль хоть и ACK оба пакета с запросом быстренько, но потом как-бы подвисает на 5секунд, и основной контент возвращает уже с задержкой.
При этом если тот же GET запрос делать через curl, который не вызывает retransmission (почему не знаю) то ответ модуля всегда приходит быстро, без задержек.
5 секунд это, насколько я понимаю, какой-то таймаут у TCP стека ESP8266.
Мне кажется что получение retransmission пакета запроса вводит TCP стек ESP8266 в ступор.
Не в ступор, а хуже.
Есть вариант, что ESP согласует соединение на одни и тот-же порты, а у компа или сервера или в сети это вызывает беду, т.к. когда правильный клиент, согласно RFC первым закрыл соединение, то оно у него сидит в состоянии TIME_WAIT в течении 120 сек (и по всей трассе аналогично). A ESP лепит опять по тем-же портам, т.к. проснулся и счетчик, замещающий рандом :), считает "свободный" порт с начала списка...
Это и остальное вы никогда не вылечите у ESP, т.к. для этого надо добавить от 200+ килобайт памяти и скорости CPU, даже на ваших вялых соединениях.
Для уточнения нужна вся история запросов. Иначе - гадание на .....
 

pvvx

Активный участник сообщества
Ущё - как в пакет с MSS 536 байт влезет заголовок?
Chrome офигеет. IE кидает запросы на канал для уточнения MSS и адаптирует заголовок HTTP под полученные данные. Но ESP не имеет такого сервиса :)
Даже если всё правильно описали в части socket и принимают полный WIN, но он у вас 2144 байта :) В него не лезет заголовок HTTP от современного браузера... А дальше козявки Arduino с разбором заголовка в буфере по дцать байт :)
Ранее, года 3 ещё назад с этим глючили большинство *nix, но им на это стали сильно указывать лет 5 назад и постепенно, частично, исправили и даже публиковали таблички у кого какой размер заголовка отрабатывает без багов :) Но забыли проверить побайтовую передачу... :) А уж в Arduino... :) Но ныне опять наплодились Ардуинщики, да напихали своей фигни, т.к. RFC они никогда не читали, и нужно снова исправлять... Во всяком случае у 90% *nix снова нарушен базовый rfc793, а уж у более мелких писателей - там вообще не знают что есть rкакие-то RFC...
Вечный круговорот - поправят, приходят новые и снова...
 

pvvx

Активный участник сообщества
И третье гадание – Espressif вставили в Lwip увеличение периода таймера опроса состояния буферов и соединений. Не на много – в тысячи раз от рекомендованного :) Это включается во всех “энерго-понижалках” для увеличения глюков и у LwIP и системы возникают запоры, до reboot по WDT и типа. Вместо рекомендованных 25 ms там увеличивают ход таймера до нескольких секунд, по которым в Lwip вызываются процедуры разборки с текущими буферами и состояниями pcb…

Отключите эту “энерго-понижалку – глюко-повышалку”.
 
Много интересных мыслей, спасибо. Надо обдумать.
C TIME_WAIT да, проблемка может выйти забористая.

Насчет заголовка не влезающего в MSS, запросы делаются между двумя автоматическими системами, без браузера. Заголовки всегда маленькие, весь пакет запроса 189 байт, заголовок ответа 147 байт.

>>
GET /get/status HTTP/1.1
Accept-Encoding: identity
Host: X.X.X.106:9980
User-Agent: Python-urllib/3.6
Connection: close
<<
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 212
Connection: close

HTTP в качестве протокола обмена был выбран в связи с легкостью отладки. Но уже возникают сомнения, ESP8266WebServer не шибко удобен/надёжен.

Не подскажите, как мне узнать текущую прошивку модуля?
Стоит ли попробовать перешить на последнюю? Я сунулся было по описанию, а там виндус требуется для утилиты xtcom_util.

И третье гадание – Espressif вставили в Lwip увеличение периода таймера опроса состояния буферов и соединений. Не на много – в тысячи раз от рекомендованного :) Это включается во всех “энерго-понижалках” для увеличения глюков и у LwIP и системы возникают запоры, до reboot по WDT и типа. Вместо рекомендованных 25 ms там увеличивают ход таймера до нескольких секунд, по которым в Lwip вызываются процедуры разборки с текущими буферами и состояниями pcb…

Отключите эту “энерго-понижалку – глюко-повышалку”.
 

pvvx

Активный участник сообщества
Режим MODEM для WiFi обычно включен по умолчанию.

Все интеллектуальные “зеленые” режимы работают по анализу кол-ва пакетов за время. У вас всего один запрос на период beacon (102.4 ms по умолчанию), что говорит о том, что режим энергосбережения будет включен. А если он включился, и тем более LIGH_SLEEP, то CPU будет отключен на периоды между beacon, как и любые прерывания…
 

pvvx

Активный участник сообщества
Но это ещё ладно (всякие MODEM/LIGHT_SLEEP), а главное то, что когда автомат будет отключать режим понижения потребления и всякие DTIM( n ) он не будет восстанавливать период отработки таймера для Lwip (стека обработки TCP/IP и т.д.).
 

pvvx

Активный участник сообщества
Такое впечатление что на TCP пакет с запросом модуль не успевает ответить за время TCP_RTO_MIN (200 ms), и линукс шлет retransmission пакет.
В честь чего он шлет retransmission ?
Пауза по ping в сетях IP определена как раз как 2*60 сек (2msl timeout) (и не случайно равна TIME_WAIT).
Таймер 2MSL заставляет клиента ждать в течение времени, достаточного для потери ACK (один MSL)

Скорее всего retransmission возник от непонимания что происходит со стеком TCP. А какие причины - по краткому логу в картинке сказать сложно
 

pvvx

Активный участник сообщества
Из сего вытекает, что не получен ACK по предыдущим пакетам в WIN в течение TCP_RTO_MIN. А отсылка ACK производится не самим сокетом, а драйвером TCP стека – в даyном случае LwIP.
Но при опции WiFi Sleep “MODEM” или “LIGH_SLEEP” обращение к LwIP, т.е. передача ему управления для счета всяких задержек происходит с периодом гораздо большим чем TCP_RTO_MIN.
Espressif считает что ESP не обязан быть совместимым с Linux и прочими нормам сетей IP. Для ESP требуется своя сеть и серверы.
 

pvvx

Активный участник сообщества
Не подскажите, как мне узнать текущую прошивку модуля?
Стоит ли попробовать перешить на последнюю? Я сунулся было по описанию, а там виндус требуется для утилиты xtcom_util.
Узнавать версию не имеет никакого смысла. Если в другой версии что-то изменено, что прокатит в этой ситуации, то остальное всё равно не совместимо с IP и тем более TCP. Т.е. всё равно будут глюки и бардак в сети от ESP, т.к. у ESP не хватает ресурсов для выполнения базовых RFC в части IPv4 и тем более TCP.
ESP32/8266 - это игрушка для ознакомления с основами WiFi. На большее она не рассчитана.
 

pvvx

Активный участник сообщества
Ещё интересная ситуация с TCP_RTO_MIN для WiFi (забудем о ESP).

Если оно равно 200 ms, то у WiFi период beacon по умолчанию 102.4 ms. Большинство “зеленых” алгоритмов работает по кол-ву пакетов. Например если за время периода паузы beacon проходит 1 или 2 пакета, то происходит переход к DTIM( n ), где n обычно от 2-х. А это от 204.8 ms. И за это время + согласование с AP выхода из этого режима никаких пакетов не передается. AP должна буферизировать проступившие запросы (что в реальности не всегда на дешевых роутерах – просто отбросит и оставит последний)… Т.е. в сети будут обязательные retransmission у неверно настроенного клиента с TCP_RTO_MIN в 200 ms со всеми WiFi устройствами. Лишний засор сети :)
 

pvvx

Активный участник сообщества
С UDP-шниками тут вообще смех и грех.
 
Сверху Снизу