Ошибка HTTP-запроса Arduino, медленное сотовое соединение

Настройка:

  • Arduino Mega 2560 с Ethernet-щитом Wiznet W5500

  • Использование маршрутизатора TP-Link TL-MR6400 LTE для подключения к Интернету по сотовой связи в Уганде.


Используя публикацию HTTP со следующим:

client.println("POST /hook HTTP/1.1");
client.print("Host: "); client.println(server);
client.println("Accept: */*");
client.print("Content-Type: text/html;");
client.println("User-Agent: Arduino/1.0");
client.println("Connection: close");
client.print("Content-Length: ");
client.println(PostData.length());
client.println();
client.println(PostData);

где PostData — это String, а Ethernet2 — используемая библиотека.

Это прекрасно работает из США на тот же сервер AWS или экземпляр https://requestbin.com/.


При тестировании из Уганды с использованием Raspberry Pi и curl все работает нормально.

$ curl -vs -d 'ABCDEFG' -H "User-Agent: Arduino/1.0"  -H "Content-Type: text/html" -H "Connection: close"   http://<server here>/hook
*   Trying <ip here>...
* TCP_NODELAY set
* Connected to <server here> (<ip here>) port 80 (#0)
> POST /tg HTTP/1.1
> Host: <server here>
> Accept: */*
> User-Agent: Arduino/1.0
> Content-Type: text/html
> Connection: close
> Content-Length: 7
> 
* upload completely sent off: 7 out of 7 bytes
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Content-Type: application/json; charset=utf-8
< Date: Tue, 06 Aug 2019 21:06:49 GMT
< x-pd-status: sent to primary
< X-Powered-By: Express
< Content-Length: 16
< Connection: Close
< 
* Curl_http_done: called premature == 0
* Closing connection 0
{"success":true}

Я даже попробовал пример HTTP GET из библиотеки Ethernet2,

https://www.arduino.cc/en/Tutorial/WebClientRepeating

В США это работало нормально, но в Уганде я получаю

My IP address: 192.168.1.177

connecting...

connecting...

connecting...

Я увеличил время между запросами здесь до 100 секунд, при этом он прослушивается все время между ними.

Похоже, что client.connect(server, 80) выполнено успешно, и сообщения client.print проходят, но сообщение никогда не достигает сервера, поэтому ответа нет. . Мой сервер AWS не получает запрос, и это то же самое для экземпляра requestbin. Это поведение отражено во всех моих тестах Arduino.

Я думал, что интернет-провайдер может блокировать, но RPi может отправить почти такое же сообщение. Думал может таймаут где-то но не могу найти где своими тестами. Я думал, что мое сообщение было слишком длинным, но я уменьшил его размер до 10 символов с теми же результатами.


Пытаемся выяснить, почему HTTP-запрос Arduino не может получить веб-перехватчики из Уганды, и как это исправить, если это возможно. Другой провайдер, более медленное соединение, сотовая связь?

Любая помощь будет оценена по достоинству.

, 👍1

Обсуждение

@jsotola да, я могу подключиться к любому серверу с помощью Raspberry Pi в той же сети, что и Arduino в Уганде (подключенной к тому же маршрутизатору). Я также могу подключиться к обоим серверам с обеими попытками скетчей Arduino из США. Я здесь рассматриваю Raspberry Pi как компьютер., @jmb2341

мои извинения, я не внимательно прочитал ваш пост ... вы уже объяснили, что Pi подключается правильно, @jsotola

попробуйте библиотеку Ethernet, @Juraj

Единственное, что я могу придумать, это попробовать HTTP/1.0 вместо HTTP/1.1. Или, может быть, объединить все client.print, чтобы все отправлялось в одном пакете, а не в нескольких (я не мог понять, так ли это)., @Gerben

да, используйте буферизацию https://github.com/jandrassy/StreamLib/blob/master/README.md, @Juraj

@Juraj Ваше решение сработало для меня, если вы опубликуете ответ, я его приму. В качестве фона я пробовал Ethernet lib по сравнению с Ethernet2, я пробовал HTTP/1.0 против HTTP/1.1, а также добавлял только оператор client.flush() после моих запросов. Я попытался использовать только IP-адрес, чтобы избежать DNS-запросов и ускорить процесс, используя другой, более быстрый DNS, например 1.1.1.1 или 8.8.8.8. Наконец, две вещи, которые помогли, заключались в том, чтобы поддерживать соединение открытым, когда это возможно, с помощью Connection: Keep-Alive и примера библиотеки [StreamLib](https://github.com/jandrassy/StreamLib) ChunkedPrint., @jmb2341


1 ответ


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

1

Буферизация и сброс()

Многие библиотеки Arduino страдают от медленной связи, потому что авторы не использовали буферизацию. Чтобы не отправлять каждый небольшой фрагмент данных по соединению с накладными расходами байтов протокола, используйте буферизацию. Данные собираются до тех пор, пока буфер не заполнится, а затем собранные данные отправляются, и буфер готов для следующих байтов. Функции flush() отправляют буфер, даже если он не заполнен, но у вас нет больше данных. («Дилемма» flush() была решена, и в основных классах Arduino метод flush() объявлен в классе Print, который является стандартным интерфейсом Arduino для выходных потоков.)

Моя библиотека StreamLib предлагает класс BufferedPrint, который упаковывает целевой поток и буферизует данные для отправки по целевому потоку. Конечно, не забудьте использовать flush() после печати последних данных.


Длина данных HTTP

В скетчах Arduino принято не отправлять заголовок Content-length с запросами POST. В большинстве случаев это связано с тем, что при отправке заголовков HTTP размер данных неизвестен. Затем веб-сервер не знает, получил ли он все данные, и ждет, пока соединение не будет закрыто или не будет достигнут тайм-аут. Это приводит к долгому времени, пока веб-сервер не отправит ответ на запрос скетча Arduino.

Если данные можно преобразовать в строку в памяти, заполните HTTP-заголовок Content-length.

Если данные, которые должны быть отправлены в ответ или в запросе POST, не помещаются в доступную память, ChunkedPrint из моей StreamLib можно использовать с HTTP-кодированием Transfer-Encoding. А ChunkedPrint является расширением BufferedPrint, поэтому веб-сервер без промедления обрабатывает ваш запрос.

,