Большие (иш) строки не могут быть отправлены через WiFi101 с использованием WiFiServer

Я создал эскиз на основе примеров стандартного сервера WiFi101.

Если я определяю константный массив символов следующим образом:

const char HTML_index[] = "<html><head></head><body>test</body></html>";

Сервер работает хорошо. Однако если я увеличу размер char[] примерно до 1300 байт, сервер не сможет отправить ответ. Устройство (Feather M0 WiFi) не блокируется, я могу продолжать отправлять HTTP-запросы, последовательная консоль работает правильно, но HTTP-ответа нет. Устройство и ноутбук (клиент) подключены к одной и той же точке доступа Wi-Fi, поэтому ничего странного в этом нет.

Сначала я подумал, что это проблемы с памятью, но, поскольку я использую более новую архитектуру и IDE, используя const, следует убедиться, что строка находится во FLASH.

Поэтому я затем прочитал несколько тем об ограничениях буфера на ответ с использованием других библиотек: https://github.com/esp8266/ Ардуино/проблемы/3205

Но опять же не уверен, насколько это применимо к системе на базе ARM/библиотеке WiFi101.

Существует ли в моей настройке ограничение размера буфера и т. д. при отправке HTTP-данных? Нужно ли мне разделить строку на более мелкие части и отправить несколько ответов? Как я могу исправить эту ситуацию?

Изменить: Это пример эскиза, на котором основан мой код: https://www.arduino.cc/en/Tutorial/Wifi101SimpleWebServerWiFi

Edit2: ок, я думаю, что знаю, что происходит, но не могу проверить прямо сейчас, опубликую ответ, когда сделаю. Я нашел эту ветку https://github.com/arduino-libraries/WiFi101/issues/163, которая говорит о SOCKET_BUFFER_UDP_SIZE. Итак, я просмотрел источник WiFi101 и нашел следующее:

#ifdef LIMITED_RAM_DEVICE
#define SOCKET_BUFFER_SIZE 64
#else
#define SOCKET_BUFFER_SIZE 1472
#endif

https://github.com/arduino-libraries/WiFi101/blob /master/src/utility/WiFiSocket.cpp

Вероятно, моя строка на самом деле превышала 1472 байта, так что это имеет смысл.

Редактировать3: Нашел больше ссылок:

https://github.com/arduino-libraries/ArduinoHttpClient/issues/14

https://github.com/arduino-libraries/WiFi101/pull/116

Я так понимаю, что 1500 в WINC1500 может означать размер буфера. В любом случае похоже, что существует аппаратный предел буфера, и ответы размером более ~ 1400 байт должны быть разбиты на фрагменты.

, 👍0

Обсуждение

в примерах не используется const char HTML_index[]. покажите эскиз, который вы используете. вы устанавливаете заголовок Content-Leth?, @Juraj

Скоро я добавлю урезанный пример эскиза. Но он в точности соответствует этому примеру, за исключением того, что я определяю const char HTML_index[] = "..."; в глобальной области и вызовите client.print(HTML_index); в контуре подключения клиента. https://www.arduino.cc/en/Tutorial/Wifi101SimpleWebServerWiFi, @Geordie

попробуйте добавить задержку перед client.stop(), @Juraj

Я попробую, но поскольку в моем HTTP-заголовке не указано Connection: выполнение close остается в цикле while (client.connected()) и не затрагивает client.stop(). Но, возможно, это проблема, @Geordie


1 ответ


Лучший ответ:

1

Согласно моим заметкам, WINC1500 имеет ограничение в 1500 байт на передачу. Но часть этого всегда поглощается издержками TCP, поэтому буфер полезной нагрузки должен быть меньше, поэтому вы видите такие числа, как 1460.

От: http://ww1.microchip. com/downloads/en/appnotes/atmel-42739-tcp-client-and-server-operation-using-atwinc1500_at14596_applicationnote.pdf

2.2.2 Размер TCP-пакета

Размер пакета определяется наименьшим MTU (максимальным Transmission Unit) по пути, который обычно составляет 1500 байт (для Ethernet) данных, включая заголовки TCP (20 байт) и IP (20 байт). Размер пакета определен в main.h как:

#define MAIN_WIFI_M2M_BUFFER_SIZE 1460 

Затем приложение определяет буфер сокета такого размера в main.c как:

static uint8_t gau8SocketTestBuffer[MAIN_WIFI_M2M_BUFFER_SIZE];

Это означает, что HTTP-ответы размером более ~1400 байт должны быть разбиты на фрагменты, что означает разделение на несколько вызовов.

К вашему сведению, в HTTP/2 заменено фрагментированное кодирование передачи: < a href="http://undertow.io/blog/2015/04/27/An-in-eepse-overview-of-HTTP2.html">http://undertow.io/blog/2015/04/ 27/Углубленный обзор-HTTP2.html

Информация о фрагментированном кодировании HTTP: https://developer.mozilla.org/en-US/docs/Web/ HTTP/заголовки/кодирование передачи

Transfer-Encoding: chunked

Данные отправляются сериями блоков. Заголовок Content-Length в этом случае опущено, и в начале каждого фрагмента вам необходимо добавьте длину текущего фрагмента в шестнадцатеричном формате, а затем '\r\n', а затем сам фрагмент, за которым следует еще один '\r\n'. завершающий чанк является обычным чаном, за исключением того, что его длина равна нулю. За ним следует трейлер, состоящий из (возможно, пустая) последовательность полей заголовка объекта.

https://www.httpwatch.com/httpgallery/chunked/

https://gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88

Кодирование передачи

Использование Transfer-Encoding: chunked позволяет осуществлять потоковую передачу внутри один запрос или ответ. Это означает, что данные передаются фрагментированным образом и не влияет на представление контент.

Официально HTTP-клиент предназначен для отправки запроса с заголовком TE. поле, указывающее, какие кодировки передачи использует клиент готов принять. Оно не всегда отправляется, однако большинство серверов предположим, что клиенты могут обрабатывать фрагментированные кодировки.

Частное кодирование передачи позволяет лучше использовать постоянный TCP соединения, которые HTTP 1.1 считает истинными по умолчанию.

Фрагментированные данные представлены следующим образом:

4\r\n
Wiki\r\n
5\r\n
pedia\r\n
e\r\n
 in\r\n\r\nchunks.\r\n
0\r\n
\r\n

Каждый фрагмент начинается с длины в байтах, выраженной в шестнадцатеричном формате. номер, за которым следуют необязательные параметры (расширение чанка) и завершающая последовательность CRLF, за которой следуют данные фрагмента. Последний кусок завершается последовательностью CRLF.

Расширения чанка можно использовать для обозначения дайджеста сообщения или предполагаемый прогресс. Это просто пользовательские метаданные, которые ваш уровень 7 получателю необходимо проанализировать. Для него не существует стандартизированного формата. По этой причине, вероятно, лучше просто добавить свои метаданные (если любой) в сам чанк для анализа вашего приложения уровня 7.5.

Чтобы ваше приложение могло отправлять фрагментированные данные, вы должны сначала отправить заголовок Transfer-Encoding, а затем необходимо сбросить содержимое в фрагменты в соответствии с форматом фрагментов. Если у вас нет подходящего HTTP-сервер, который обрабатывает это, вам необходимо реализовать синтаксис генератор самостоятельно. Иногда вы можете использовать библиотеку для предоставления абстрактный интерфейс.

Возможное решение на платформах Arduino — использовать библиотеку StreamLib или собственную систему фрагментирования.

Обновление: Я собрал эскиз и подтвердил, что это работает. Следующая проблема заключалась в том, что буфер должен заканчиваться нулем, НО он удаляется перед передачей по TCP, поэтому размер фрагмента HTTP равен размеру буфера -1.

,