WEB клиент Ethernet.h

Здравствуйте. В продолжении темы на старом форуме, есть несколько поросов.

Спойлер
#include <SPI.h>
#include <Ethernet.h>
#include <avr/wdt.h>

#define PORT_NUMBER 80

const uint8_t mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const uint8_t ip[] = {192, 168, 1, 88};
const uint8_t gateway[] = {192, 168, 1, 1};
const uint8_t subnet[] = {255, 255, 255, 0};
const uint8_t dns[] = {192, 168, 1, 1};
const uint8_t server[] = {192, 168, 1, 42};
EthernetClient client;

void setup() {
  wdt_disable();
  Serial.begin(9600);
  Ethernet.begin(mac, ip, dns, gateway, subnet);
  Serial.println("Start");
  wdt_enable(WDTO_8S);
}


void http_request_get() {
  client.stop();
  if (client.connect(server, PORT_NUMBER)) {
    Serial.println("СONNECTED");
    client.print(F("GET /12.php?text=12345 HTTP/1.1\r\n"));
    client.print(F("User-Agent: ARDUINO\r\n"));
    client.print(F("Host: "));
    for (uint8_t i = 0; i < 4; i++) {
      client.print(server[i]);
      if (i < 3)client.print(".");
    }
    client.print(F("\r\n"));
    client.print("Connection: close\r\n");
    client.print("\r\n");
  } else {
    Serial.println("CONNECTION_FAILED");
  }
}




void http_request_post() {
  client.stop();
  if (client.connect(server, PORT_NUMBER)) {
    client.print(F("POST /12.php HTTP/1.1\r\n"));
    client.print(F("User-Agent: ARDUINO\r\n"));
    client.print(F("Host: "));
    for (uint8_t i = 0; i < 4; i++) {
      client.print(server[i]);
      if (i < 3)client.print(".");
    }
    client.print(F("\r\n"));
    client.print(F("Content-Type: application/x-www-form-urlencoded\r\n"));
    client.print(F("Content-Length: 9 \r\n"));
    client.print(F("\r\n"));
    client.print(F("text=1234"));
  } else {
    Serial.println("CONNECTION_FAILED");
  }
}


void get_response() {
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
}


void loop() {
  wdt_reset();
  get_response();

  static uint32_t timer_status;
  if (millis() - timer_status >= 500) {
    timer_status = millis();
    Serial.print("Status = ");
    Serial.print(client.connected());
    Serial.println("");
  }


  static uint32_t timer;
  if (millis() - timer >= 5000) {
    timer = millis();
    http_request_get();
    //http_request_post();
  }

}

<?php
	if (isset($_GET['text'])) {
		echo ("Text_GET = {$_GET['text']}\r\n");	
	}
	
	if (isset($_POST['text'])) {
		echo ("Text_POST= {$_POST['text']}\r\n");	
	}
	
?>

При выполнении GET запроса клиент сразу после отправки “останавливается”

Спойлер

Start
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
СONNECTED
HTTP/1.1 200 OK
Date: Fri, 30 Dec 2022 12:01:52 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 18
ConnectioStatus = 1
n: close
Server: Apache
X-Content-Type-Options: nosniff

Text_GET = 12345
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0

А при выполнении POST запроса

Спойлер

Start
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
HTTP/1.1 200 OK
Date: Fri, 30 Dec 2022 12:04:20 GMT
Content-Type: text/html; charset=UTF-8
Content-LengthStatus = 1
: 17
Connection: keep-alive
Keep-Alive: timeout=120
Server: Apache
X-Content-Type-Options: nosniff

Text_POST= 1234
Status = 1
Status = 1
Status = 1
Status = 1
Status = 1
Status = 1
Status = 1

Клиент после выполнения запроса не остановится.
Если строку client.stop(); перенести сразу после выполнения запроса, нужно делать задержку, примерно 100 мс, чтобы данные отправились.
Как отследить что данные отправились и остановить клиент ? (чтобы не ждать 100 мс, а остановить по факту). Ожидать строку HTTP/1.1 и останавливать?

Нет. Аливье нужно резать.

3 лайка

Клиент после выполнения запроса не остановится. :slight_smile:

рано еще!
а вот накатить уже можно :wine_glass:

3 лайка

Это всегда можно!

2 лайка

Так вы сами серверу говорите отключиться после отправки данных.
т е после http_request_get(); обнуляете таймер, в течении пары секунд в цикле проверяете client.connected() если да - проверяете client.available() - выплевываете ответ сервера, по окончании таймера принудительно вызываете stop.

С Get понятно

if (client.connect(server, PORT_NUMBER)) {  // открыла соединение
client.print(F("GET /12.php?text=12345 HTTP/1.1\r\n"));

client.print("Connection: close\r\n");// Закрыла

А с Post открыла

  if (client.connect(server, PORT_NUMBER)) {
    client.print(F("POST /12.php HTTP/1.1\r\n"));

И далее client.connect(server, PORT_NUMBER) будет true пока не client.stop();

Я прочитала что
uint8_t connected();
Описание:
Определяет есть ли подключение к серверу.
Клиент считается подключённым, если подключение уже закрыто, но остались несчитанные данные.

После выполнения post запроса client.connected() true .

Спойлер

Новый год мы праздновать будем у свекрови, потому никаких приготовлений салатиков, в гостях :grinning: :grinning: :grinning:

    client.print(F("\r\n"));
    client.print(F("Content-Type: application/x-www-form-urlencoded\r\n"));
    client.print(F("Content-Length: 9 \r\n"));
    client.print(F("\r\n"));
    client.print(F("text=1234"));
    client.stop();

Вот так не произойдёт отправка. Если закрыть соединение минимум через 100 мс, тогда client.connected() false.

а что вы мучаетесь? секунду данные входящие (ответ сервера) ждете и тупо закрываете.
ЗЫ. Хотите разобраться? - лезем в исходники библиотеки :slight_smile:
Я так понимаю что W5500 используете? Тогда напрямую читаете регистры сокета, там все написано, и соединение есть/нет, и есть или нет входящие данные непрочитанные.

Да. Она самая.
Или отправляю данные, обновляю таймер.
Если в течении 2 секунд client.available() ничего не прочитал, останавливаю клиент, если прочитал, обновляю таймер.

зачем? все равно больше данных не получите от сервера, имеет смысл сразу все остановить.

ну и вот для чтения/размышления, может сами прикрутите wiznet библиотеку к Arduino - более глубоко будете рулить сокетами.
GitHub - Wiznet/ioLibrary_Driver: ioLibrary_Driver can be used for the application design of WIZnet TCP/IP chips as W5500, W5300, W5200, W5100 W5100S.
https://forum.cxem.net/applications/core/interface/file/attachment.php?id=709523
W5500, ИС Ethernet контроллер datasheet на русском. Качайте) - Справочная радиоэлементов - Форум по радиоэлектронике (cxem.net)

Значит, если не вникать в сокеты, просто остановить через, скажем, пол секунды.
То есть остановить через 500 мс после последнего полученного символа из client.available()

Скетч

Спойлер
#include <SPI.h>
#include <Ethernet.h>
#include <avr/wdt.h>

#define PORT_NUMBER 80

const uint8_t mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const uint8_t ip[] = {192, 168, 1, 88};
const uint8_t gateway[] = {192, 168, 1, 1};
const uint8_t subnet[] = {255, 255, 255, 0};
const uint8_t dns[] = {192, 168, 1, 1};
const uint8_t server[] = {192, 168, 1, 42};
EthernetClient client;

void setup() {
  wdt_disable();
  Serial.begin(9600);
  Ethernet.begin(mac, ip, dns, gateway, subnet);
  Serial.println("Start");
  wdt_enable(WDTO_8S);
}

bool request_post = false;
uint32_t request_post_tmr;

void http_request_post() {
  if (client.connect(server, PORT_NUMBER)) {
    client.print(F("POST /12.php HTTP/1.1\r\n"));
    client.print(F("User-Agent: ARDUINO\r\n"));
    client.print(F("Host: "));
    for (uint8_t i = 0; i < 4; i++) {
      client.print(server[i]);
      if (i < 3)client.print(".");
    }
    client.print(F("\r\n"));
    client.print(F("Content-Type: application/x-www-form-urlencoded\r\n"));
    client.print(F("Content-Length: 9 \r\n"));
    client.print(F("\r\n"));
    client.print(F("text=1234"));

    request_post = true;
    request_post_tmr = millis();
  } else {
    Serial.println("CONNECTION_FAILED");
    client.stop();
  }
}



void get_response() {
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
    request_post_tmr = millis();
  }
}


void loop() {
  wdt_reset();
  get_response();

  if (request_post && millis() - request_post_tmr >= 500) {
    Serial.println("CLIENT_STOP");
    request_post = false;
    client.stop();
  }


  static uint32_t timer_status;
  if (millis() - timer_status >= 500) {
    timer_status = millis();
    Serial.print("Status = ");
    Serial.print(client.connected());
    Serial.println("");
  }


  static uint32_t timer;
  if (millis() - timer >= 5000) {
    timer = millis();
    http_request_post();
  }

}

Монитор порта

Спойлер

Start
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
Status = 0
HTTP/1.1 200 OK
Date: Fri, 30 Dec 2022 14:06:46 GMT
Content-Type: text/html; charset=UTF-Status = 1
8
Content-Length: 17
Connection: keep-alive
Keep-Alive: timeout=120
Server: Apache
X-Content-Type-Options: nosniff

Text_POST= 1234
Status = 1
CLIENT_STOP
Status = 0
Status = 0
Status = 0

Лень в лог вникать, с телефона читать - работает?
Я б вообще отключал через секунду после отправки, вне зависимости от приёма данных.
А в сокеты надо вникать :slight_smile: - пригодиться.

Работает.

после 45 строки delay(10);
далее проверяем статус переданного
У меня так, работает годами, ни одного сбоя

  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  client.stop();
  delay(10);

  // читаем ответ с и отправляем его в сериал
  // вообще на ответ нужно как-то реагировать
#ifdef DEBUG
  Serial.print("Requesting: ");
#endif
  while (client.available()) {
    String line = client.readStringUntil('\r');
#ifdef DEBUG
    Serial.print(line);
#endif
  }  //

Как оффтоп:
Я вот вспоминаю времена когда я «входил» в говнокодство веб, там за каждый байт «дрались». Страница должна была максимум за 30 секунд загружаться, и это на скорости олддиплап!

Get То да, Connection: close,а при выполнении пост нет Connection: close

у меня и пост работает годами, примера под рукой нет, там я еще и SHA применяю

ЗЫ ESP8266

Это совсем другая разница)

знаю, W5500 другой стек, да и памяти сильно поменьше
PS это лишний раз подтверждает слова, что процессор надо подбирать под задачу