Зависает EthernetClient

Darkherald
Offline
Зарегистрирован: 30.08.2019

Здравствуйте может кто-то уже сталкивался WebClient с W5500 и библиотекой Ethernet2.h или ENC28J60 с UIPEthernet.h. Проблема заключается в зависании подключения client.connect(server, 80)). Раз в минуту идет подключение к серверу методом client.connect(server, 80)) и отправка get или post запроса на данный сервер. Но бывает спустя энное количество времени при очередном подключении к серверу он становиться недоступен (хотя сам ресурс доступен). Помогает только перезагрузка arduino.

Как это можно победить?

sadman41
Offline
Зарегистрирован: 19.10.2016

Искать причину, фиксить, тестировать, ошибаться, вновь искать, опять фиксить, снова тестировать и т.д.

Вкратце - такой алгоритм.

nik182
Offline
Зарегистрирован: 04.05.2015

Последить за свободной памятью. 

sadman41
Offline
Зарегистрирован: 19.10.2016

nik182 пишет:

Последить за свободной памятью. 

Или проверить на предмет keep-alive. И проверить ещё стотыщ вероятных мест, о которых мы должны гадать, в ответ на что  аффтар будет снисходить до очередной проверки и констатации факта - угадали или нет.

Darkherald
Offline
Зарегистрирован: 30.08.2019

nik182 пишет:

Последить за свободной памятью. 

В сетевых модулях или ардуине? 

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

Или проверить на предмет keep-alive. И проверить ещё стотыщ вероятных мест, о которых мы должны гадать, в ответ на что  аффтар будет снисходить до очередной проверки и констатации факта - угадали или нет.

Можно пример запроса с keep-alive?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:
мы должны гадать
И это правильно. Ибо, как нам объяснили в соседней теме, выкладывать информацию, смысла нет.

sadman41
Offline
Зарегистрирован: 19.10.2016

Darkherald пишет:

sadman41 пишет:

Или проверить на предмет keep-alive. И проверить ещё стотыщ вероятных мест, о которых мы должны гадать, в ответ на что  аффтар будет снисходить до очередной проверки и констатации факта - угадали или нет.

Можно пример запроса с keep-alive?

Пример запроса: https://www.google.com/search?q=keep+alive+network+connection

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

Darkherald пишет:

sadman41 пишет:

Или проверить на предмет keep-alive. И проверить ещё стотыщ вероятных мест, о которых мы должны гадать, в ответ на что  аффтар будет снисходить до очередной проверки и констатации факта - угадали или нет.

Можно пример запроса с keep-alive?

Пример запроса: https://www.google.com/search?q=keep+alive+network+connection

Неправильно выразился. Можете помочь внедрить данный запрос в стандартный код веб клиента? под W5500  и библиотекой Ethernet2.h

sadman41
Offline
Зарегистрирован: 19.10.2016

Ни разу не встречался с тем, чтобы при качественном монтаже стандартный пример WebClient зависал с визнетовскими чипами. 

Заняться выловом багов я могу, конечно. 

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

Ни разу не встречался с тем, чтобы при качественном монтаже стандартный пример WebClient зависал с визнетовскими чипами. 

Заняться выловом багов я могу, конечно. 

Тут 2 основных момента.

1. Принимает POST запрос Apache

2. client.connect вызывается в определенный момент для отправки POST запрос. (В стандартных примерах. client.connect поднимается 1 раз в Setup. Но при таком примере Apache принудительно закрывает соединение после отправки ответа клиенту).

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

sadman41
Offline
Зарегистрирован: 19.10.2016

Способ передачи в TCP-сессии вполне надёжный способ. И POST я делал и GET и просто в сокет забрасывал данные. Никаких зависаний в девайсах не наблюдаю.

А вообще - Вам не кажется, что диалог беспредметный? Все равно, что позвонить в автосервис и спросить: "Почему она не едет, если я на газ давлю? У кого-нибудь ещё такое было?"

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

Способ передачи в TCP-сессии вполне надёжный способ. И POST я делал и GET и просто в сокет забрасывал данные. Никаких зависаний в девайсах не наблюдаю.

А вообще - Вам не кажется, что диалог беспредметный? Все равно, что позвонить в автосервис и спросить: "Почему она не едет, если я на газ давлю? У кого-нибудь ещё такое было?"

Как у Вас соединение поднимается? В setup или loop?. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Соединение поднимается по мере необходимости. Не единственный раз за всё время работы устройства.

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

Соединение поднимается по мере необходимости. Не единственный раз за всё время работы устройства.

Я правильно понимаю. Ip адрес в setup, а client.connect по необходимости?

Еще один вопрос если не затруднит. 

Соединение закрывается при получении ответа от сервера? 

sadman41
Offline
Зарегистрирован: 19.10.2016

Соединение закрывается всегда, когда сессия обмена данными завершена. 

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

Соединение закрывается всегда, когда сессия обмена данными завершена. 

Можно попросить Вас? кинуть пример вашего кода поднятие клиента, чтение, закрытие соединения.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017
EthernetClient.stop();

-

вот похожий пример http сервера

http://arduino.ru/forum/proekty/ethernet-vyklyuchatel-nagruzki-v-lokalno...

 

Darkherald
Offline
Зарегистрирован: 30.08.2019
#include <SPI.h>
#include <Ethernet2.h>

byte mac[] = {0xFC, 0x9A, 0xC7, 0x52, 0xE5, 0xFE};

IPAddress server(109 , 195 , 53 , 209);
IPAddress ip(192, 168, 0, 177);
unsigned long Time;
EthernetClient client;

void setup() {
  Serial.begin(115200);
  Serial.println(F("start ..."));

  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }
  delay(1000);
  Serial.println("connecting...");

  Serial.print(F("IP = "));
  Serial.println(Ethernet.localIP());
}


void GET()
{
  Serial.println("GET");

  if (client.connect(server, 80)) {
      Serial.println("connected");

  client.println("GET /Sensor/hs/DeviceData/SetData?P3=3&Arduino HTTP/1.1");
  client.println("Host: server");
  client.println("keep-alive");
  client.println("Connection: close"); 
  client.println();
  }
  else {
    Serial.println("connection failed");  //  "подключение не удалось"
  }  
}

  void loop()
  {
    if ((millis() - Time) >= 20000)
    {
      Time = millis();
      GET();
    }

    if (client.available()) {
      char c = client.read();
      Serial.print(c);  
    }
    
    if (!client.connected()) {
        client.stop();
    }
  }

andycat Подскажите, что в данном коде не так? Почему он подвешивает W5500. Не знаю куда уже копать.

 

Logik
Онлайн
Зарегистрирован: 05.08.2014

А ты по форуму искал? Тут такие темы постоянно вылазят, что как бы намекает на наличие не решаемой проблемы.

Darkherald
Offline
Зарегистрирован: 30.08.2019

Я подозреваю, что проблема в кэше W5500. Судя по теории с источника https://radiokot.ru/forum/viewtopic.php?p=3582271

Может можно как-то проверять кэш W5500 на наличии в нем информации? для дальнейших действий с ней.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

я как то ни разу не делал именно клиентскую отправку GET через Ethernet Clent/

Код у Вас видно что взят из примера, но в примере одна отправка и все, а у вас по таймеру.

Рекомендую попробовать поменять логику:

По таймеру делать сначала Connect, если успешно то println (get запрос), и в любом случае делаем client.stop();

т.е. мне не нравиться что соединение по факту остается открытым. Ответ ответ от сервера нужен?

Darkherald
Offline
Зарегистрирован: 30.08.2019
Соединение закрывается со стороны сервера апачем (и это не изменить). Если не закрывать соединение в клиенте, то следующую отправку через 20 сек. Сервер будет недоступен.
Сейчас логика такая.
1. через 20 сек. Подключение к серверу.
2. отправка Get запроса. 
3. читаем ответ сервера
4. сервер закрывает соединение
5. в loop постоянно идет проверка доступности сервера. И как только сервер недоступен. делает stop клиента.
---------------------
Все работает хорошо, но иногда становится клином. И сервер всегда недоступен. До перезагрузки. А может и неделю проработать без затырок.
Думал наоборот поднять соединение и сделать все чтобы апачь его не закрыл, но пока не получилось. Возможно это и неправильно (постоянно держать открытое соединение).
Но если сравнивать Get запрос с обычного браузера, то соединение не закрывается сервером.
 

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Я конечно может и не прав, но http протокол и сделан для ого чтобы отправить запрос, получить ответ. Какие нафиг 20 секунд.... Смысл?

И что за странная фраза сервер закрывает соединение - где такое вычитали? Если мобильник связь потерял при чтении страницы - сервер будет до бесконечности ждать? Почитайте tcp протокол.

sadman41
Offline
Зарегистрирован: 19.10.2016

Так я и знал, что там keep-alive вкрячен.

Darkherald
Offline
Зарегистрирован: 30.08.2019

Фаза отправки и приема ответа происходит моментально. Каждые 20 секунд идет сбор данных и отправка на сервер.

Сервер закрывает соединение (это видно через Wireshark).

Так как можно еще реализовать передачу данных каждые 20 секунд?

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

Так я и знал, что там keep-alive вкрячен.

И ????? что с ним, что без него одно и тоже.

sadman41
Offline
Зарегистрирован: 19.10.2016

В данном случае stop() полагается делать на строке 39, а не черте знает где.

Darkherald
Offline
Зарегистрирован: 30.08.2019

sadman41 пишет:

В данном случае stop() полагается делать на строке 39, а не черте знает где.

А читать информацию когда? если после отправки отключим клиента?

sadman41
Offline
Зарегистрирован: 19.10.2016

Что Вы с ней делаете, с информацией этой?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Darkherald пишет:

sadman41 пишет:

В данном случае stop() полагается делать на строке 39, а не черте знает где.

А читать информацию когда? если после отправки отключим клиента?

1 логику включите, если у вас мгновенно (относительно) идёт отправка - ничего не мешает по таймеру приём данных обеспечить и отключиться через секунду две
2 вместо того чтоб спорить - попробовали бы уже давно совет прописать stop после отправки без приёма, а потом бы уже принимали данные.

Darkherald
Offline
Зарегистрирован: 30.08.2019

Вы предлагаете 1 вариантом сделать считывание ответа от сервера с задержкой? Я правильно понял?

По второму.

Я не спорю. Логики не могу понять.

Если закрыть соединение, то получить данные невозможно даже спустя время (сессия закрывается).

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Darkherald пишет:

Вы предлагаете 1 вариантом сделать считывание ответа от сервера с задержкой? Я правильно понял?

По второму.

Я не спорю. Логики не могу понять.

Если закрыть соединение, то получить данные невозможно даже спустя время (сессия закрывается).

ну как же, заводите первый таймер на 20 секунд, отправляете get запрос, ставите некий флаг что необходимо прочитать ответы от сервера, запускаете таймер на 2 секунды, в течении двух секунд если client.available() читаем данные (кстати вы не ответили зачем?), две секунды прошли, stop клиенту, сбрасываем флаг и по кругу.

sadman41
Offline
Зарегистрирован: 19.10.2016

Инициированный микроконтроллером обмен данными по TCP со внешним сервером с использованием чипов Wiznet выглядит примерно так:

1) МК вызывает connect(), в котором проверяется наличие свободных сокетов (находящихся в состоянии CLOSED, FIN_WAIT, CLOSE_WAIT) чипа, при наличии таковых - сокет переводится в состояние ESTABLISHED и делается попытка установления соединение с внешним хостом;
2) Каждый print*() или write() переносит данные от МК в TX-буфер данных используемого сокета. После переноса чипу дается команда на отправку данных и он делает трансмит TX-буфера;
3) Одновременно, все входящие в TCP-сессии данные складываются в RX-буфер сокета, что вызывает изменение возвращаемой available() величины;
4) По завершению обмена данными через stop() сокет переводится в состояние CLOSED, сессия закрывается;
5) Данные, не вычитанные из RX-буфера, остаются доступными для read() и, пока они не будут вычитаны, available() возвращает положительное число, а connected() ведет себя следующим образом - "Note that a client is considered connected if the connection has been closed but there is still unread data."

Стало быть: пока МК самостоятельно не разорвёт сессию и это не сделает удалённый хост (что не факт) - сокет будет недоступен для следующего коннекта и через какое-то время connect() начнёт возвращать нуль, то есть false. 

Читать/не читать RX-буфер - действие по желанию.

Впрочем, в новых релизах библиотеки кое-что изменилось, но общий принцип тот же. UIP_Ethernet работает частично иначе.

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

Darkherald
Offline
Зарегистрирован: 30.08.2019

Спасибо за информацию. 

Непонятно по 5 пункту.  "Данные, не вычитанные из RX-буфера, остаются доступными для read()"

Если /не читать RX-буфер он сам затрется? после сброса соединения?.

Судя по описанию. Note that a client is considered connected if the connection has been closed but there is still unread data . Клиент разрывается но не разрывается для чтения. Этот момент не может повлиять на дальнейшие соединения?

sadman41
Offline
Зарегистрирован: 19.10.2016

Darkherald пишет:

Спасибо за информацию. 

Непонятно по 5 пункту.  "Данные, не вычитанные из RX-буфера, остаются доступными для read()"

Если /не читать RX-буфер он сам затрется? после сброса соединения?.

Не затрётся. Иначе бы после разрыва соединения available() сразу вернул бы 0, а connected() - false

Darkherald пишет:

Клиент разрывается но не разрывается для чтения. Этот момент не может повлиять на дальнейшие соединения?

В Вашем случае полагаю, что может.