Consigli implementazione Client-Server con arduino

Salve ragazzi, ho un dubbio piuttosto banale, però navigando un po' sul web non sono riuscito totalmente a chiarirmi le idee, dovrei utilizzare Arduino per realizzare un lettore di biglietti.
Attraverso un keypad l'utente inserisce il codice relativo al proprio biglietto, dopodiché arduino ricevuto questo codice lo invia ad un server locale che interrogando un db gli dice se il codice è valido oppure no, in base alla risposta accendo dei led di diverso colore.
Ora, tralasciando le parti relative al keypad e gestioni led abbastanza banali, il mio dubbio proprio a livello concettuale è come effettuare la comunicazione in locale tra arduino ed il server.
Dato questo vettore di char contenente il codice e supponendo di usare MQQT/HTTP per passarlo al server, come posso gestire il tutto in maniera completamente automatica?
Cioè vorrei che questo server, appena ricevuto il codice, interroghi il database ed invii la risposta senza dover fare nulla a livello manuale.

Grazie in anticipo :slight_smile:

Buongiorno,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

Scusami, mi è sfuggita la presentazione, appena fatta :wink:

Io credo che dovresti iniziare a definire lato server cosa devi/puoi fare... Come lo immagini? E quale livello hai di conoscenze di reti (TCP/IP, UDP...) e di programmazione (C#? ASP? Php?)? E soprattutto in Windows o anche Linux?

Ad esempio se lo immagini un server web dovresti scrivere (nel linguaggio che conosci e supportato da un web server, che so, C#/ASP, o php, o Python o altro...) uno script o pagina che ricevendo da Arduino una GET vada a fare l'interrogazione che ti interessa.restituendo ad Arduino la risposta. Potrebbe essere anche un Web Service, magari un semplice REST service che sarebbe la cosa migliore.

Oppure potrebbe essere un programma o un servizio dedicato (ma sempre da realizzare su PC) che stia in "ascolto" su una determinata porta TCP e ad ogni richiesta faccia la ricerca restituendo il valore.

E poi sono cose che risiedono nella stessa rete locale o devono essere "distribuite" in network diverse o addirittura devono dialogare tramite Internet?

Guarda, ti ringrazio tantissimo per la risposta, per semplificare la progettazione del tutto volevo implementare il tutto su linux
Per la parte di reti, sono messo piuttosto bene (perlomeno sulla teoria), per la parte di programmazione, tra i linguaggi che hai elencato conosco solo il PHP, ma non dovrei avere problemi nell'imparare C#/Phyton avendo già fatto come linguaggi ad oggetti C++ e Java.
Per semplicità, volevo far funzionare il tutto su rete locale, poi magari in un futuro prossimo mi porrò il problema di un approccio distribuito.
Per il protocollo di livello trasporto non ho la più pallida idea, nel senso, non so quale possa essere una scelta consona per arduino.
Dalla teoria, in breve, so che TCP offre dei servizi di controllo(Acknowleadge,controllo congestione, numerazione pacchetti ecc.) ma che è un protocollo "lento"a differenza di UDP che massimizza le prestazioni, ma può avere problemi con i firewall.
Ho visto però che MQTT si basa sul TCP ed è abbastanza usato sui dispositivi embedded essendo leggero.
Comunque grazie per gli spunti :wink:

lcfmr:
Guarda, ti ringrazio tantissimo per la risposta, per semplificare la progettazione del tutto volevo implementare il tutto su linux

Bene!

Per la parte di reti, sono messo piuttosto bene (perlomeno sulla teoria), per la parte di programmazione, tra i linguaggi che hai elencato conosco solo il PHP

E' sufficiente. Quindi Apache+PHP.

Per semplicità, volevo far funzionare il tutto su rete locale, poi magari in un futuro prossimo mi porrò il problema di un approccio distribuito.

Ok, quindi se su rete locale e se per semplicità usi Apache e php, userai il semplice TCP.

ma che è un protocollo "lento"a differenza di UDP che massimizza le prestazioni, ma può avere problemi con i firewall.

Se stai nella stessa rete locale non ci sono firewall (e comunque il problema potrebbe essere anche un semplice router), in ogni caso usa il web server Apache con php, e lato Arduino farai una chiamata HTTP GET. Se cerchi in rete (ed anche in questo forum) troverai tonnellate di informazioni, schemi e listati di esempio per fare da Arduino una chiamata HTTP verso uno script PHP....

Ho visto però che MQTT si basa sul TCP ed è abbastanza usato sui dispositivi embedded essendo leggero.

Si ma a te non serve, quello si usa soprattutto per sistemi distribuiti su rete geografica.

Perfetto ti ringrazio di tutto, un ultima curiosità, nel caso in cui dovessi estendere il tutto su internet, quindi supponendo di avere un server avente un indirizzo IP pubblico, dovrei modificare qualcosa, rispetto alle linee guida che mi hai dato tu?
A proposito, volevo farti una domanda prima ma mi ero scordato, dal mio server come faccio a capire se la GET proviene dal mio Arduino oppure da un altro dispositivo? (non su rete locale)
Perché in questo contesto, il mio Arduino avrebbe un indirizzo IP privato che viene mappato dal NAT del Router ed il Server vede l'ip pubblico del router che non è detto che sia statico.

PS. C'é qualche versione di linux che reputi migliore rispetto ad altre, per l'implementazione di un server domestico?

lcfmr:
nel caso in cui dovessi estendere il tutto su internet, quindi supponendo di avere un server avente un indirizzo IP pubblico, dovrei modificare qualcosa, rispetto alle linee guida che mi hai dato tu?

No, se ad esempio prendi un serverino Linux su Aruba registrerai magari anche un nome dominio e su Arduino userai quello invece dell'indirizzo IP del server locale.

A proposito, volevo farti una domanda prima ma mi ero scordato, dal mio server come faccio a capire se la GET proviene dal mio Arduino oppure da un altro dispositivo? (non su rete locale)
Perché in questo contesto, il mio Arduino avrebbe un indirizzo IP privato che viene mappato dal NAT del Router ed il Server vede l'ip pubblico del router che non è detto che sia statico.

nella chiamata puoi passare al server qualche tuo codice (password o token) quindi solo chi conosce quel codice (insieme all'indirizzo, ed al nome della pagina...) può fare interrogazioni, ad esempio una GET del tipo:

http://mioserver-di-casa.it/ReadValue.php?token=018491739&key=132

Il codice potrebbe anche essere variabile inventandoti un tuo algoritmo, ad esempio potrebbe contenere una parte fissa ed una parte variabile come la data di validità (es. parte fissa="a956" e parte variabile=20200326 quindi "a95620200326") per cui ne avresti una al giorno. Non che sia il massimo della sicurezza, ma è una misura valida comunque per evitare chiamate non desiderate (l'unico difetto è che se qualcuno andasse a "sniffare" le comunicazioni potrebbe vedere cosa richiami: ma non è che stai facendo transazioni finanziarie quindi la sicurezza di quel tipo è sufficiente :wink: ).

PS. C'é qualche versione di linux che reputi migliore rispetto ad altre, per l'implementazione di un server domestico?

Mah, Ubuntu è quello che va per la maggiore in ambito desktop, se parliamo di server ti direi CentOS (che di fatto è RedHat quindi di un certo livello) che è performante e gratuito. Ma nel tuo caso è indifferente, ti basta Apache e php ed ovviamente il database che sceglieresti per questa applicazione e che non so se tu già l'abbia (in caso MariaDB è anche questo gratuito e buono, altrimenti se andrai in hosting puoi usare il MySQL che in genere ti danno con i server Linux).

Guarda complimenti, sei di una chiarezza che è strepitosa, grazie di tutto :wink:

Ciao, purtroppo la chiarezza delle tue spiegazioni ha dovuto fare i conti con delle difficoltà di implementazione pratiche :D.
Ho scritto la parte dello script PHP lato server, ora dovendo gestire la parte di Arduino, che funge come client, sono partito dallo Sketch di base del Web Client, togliendo le parti reputate da me inutili, ad esempio la parte del DNS avendo già l'IP del Server:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

IPAddress server(192,168,1,80);  

IPAddress ip(192, 168, 1, 177);



EthernetClient client;


void setup() {
  
  Serial.begin(9600);
  while (!Serial);


    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) 
        delay(1);
      
    }

    if (Ethernet.linkStatus() == LinkOFF) 
      Serial.println("Ethernet cable is not connected.");
    
}
      Ethernet.begin(mac, ip);


  // give the Ethernet shield a second to initialize:

  delay(1000);
  Serial.print("connecting to ");
  Serial.print(server);
  Serial.println("...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.print("connected to ");
    Serial.println(client.remoteIP());

    // Make a HTTP request:
    client.println("GET /search?q=arduino HTTP/1.1");
    client.println("Host: www.google.com");
    client.println("Connection: close");
    client.println();
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }



}


void loop() {}

Ora tralasciando la funzione loop,vorrei prima di tutto effettuare la connessione tra host e server (ovviamente, come si può dedurre dall'IP del server, che è privato, il tutto è in locale).
La parte critica che non riesco a capire come adattare alle mie esigenze è quella della http request, in primo luogo mi è chiaro che il Request Method in questo caso è una GET perché devo passare al server un nome (Arduino) ed una pw (so che la get non è ottimale dal punto di vista della sicurezza e che dovrei utilizzare una POST, ma per ora sto implementando tutto in locale quindi non è un problema), ma la sintassi di creazione della URI mi lascia qualche dubbio, cioè non dovendo far riferimento ad un URL cosa scrivo nella URI per passare queste due informazioni?
Ho cercato un po' su internet ma non ho trovato nulla di esaustivo in merito, avrei bisogno in sintesi, di far passare con la GET delle informazioni per differenziare il servizio che il server da ai diversi client, ma non capisco come manipolare la URI per far questo.
E poi di seguito nel campo Host cosa scrivo? Non facendo riferito ad un sito :frowning:

lcfmr:
sono partito dallo Sketch di base del Web Client, togliendo le parti reputate da me inutili

Il codice che hai postato lo hai provato? Manca una graffa...
Se ti abitui ad indentare sempre il codice, te ne accorgi facilmente. Intanto premi Ctrl-T nell'IDE così te lo indenta lui e trovi l'errore.

vorrei prima di tutto effettuare la connessione tra host e server

E per fare cosa? Le connessioni HTTP sono generalmente "on demand" ossia fai la connessione al server quanto di occorre ossia devi interrogare il server per qualche ragione, non fai la connessione all'inizio e poi la tieni aperta.

La parte critica che non riesco a capire come adattare alle mie esigenze è quella della http request, in primo luogo mi è chiaro che il Request Method in questo caso è una GET perché devo passare al server un nome (Arduino) ed una pw, ma la sintassi di creazione della URI mi lascia qualche dubbio, cioè non dovendo far riferimento ad un URL cosa scrivo nella URI per passare queste due informazioni?

Ehm, ti consiglierei di studiare un poco l'HTTP per capire meglio questa cosa.

Fare una GET significa fare una connessione TCP sulla porta 80 del server (identificato dall'IP in questo caso), ed inviare il comando GET, che ha due parametri: la risorsa richiesta ed il protocollo (generalmente "HTTP/1.1" ad esempio). La risorta in genere è la pagina da richiamare, con eventuali parametri che seguono "?" e separati tra loro con "&". Quindi se tu per simulare la cosa col browser richiamassi:
http://192.168.1.50/getVal.php?key=120
devi attivare la connessione TCP sulla porta 80 a 192.168.1.50 e poi mandare il comando:
GET /getVal.php?key=120 HTTP/1.1
Ovviamente la stringa della GET la comporrai in base a ciò che devi passare al tuo php.

Ad esempio leggi QUI e QUI penso che troverai informazioni utili proprio a cose del genere.

Innanzitutto, grazie infinite che sei sempre molto disponibile nell'aiutarmi, ti rispondo ora perché ho ricercato un po' di materiale per capire come fare le cose con cognizione di causa; ho anche trovato diverse discussioni simili alla mia,ma non ho risolto,il problema è sulla connessione al server.

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
IPAddress server(192,168,1,80);  // numeric IP for Google (no DNS)
//char server[] = "www.google.com";    // name address for Google (using DNS)

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);
IPAddress myDns(192, 168, 0, 1);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;


unsigned long byteCount = 0;
bool printWebData = true;  // set to false for better speed measurement

void setup() {

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) {
        delay(1); // do nothing, no point running without Ethernet hardware
      }
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip, myDns);
  } else {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.print("connecting to ");
  Serial.print(server);
  Serial.println("...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.print("connected to ");
    Serial.println(client.remoteIP());
    // Make a HTTP request:
    client.println("GET /esempio.php?Username=Arduino HTTP/1.1");
    client.println("Host: 192.168.1.80");
    client.println("Connection: close");
    client.println();
    client.println();
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }

}

void loop() {

  int len = client.available();
  if (len > 0) {
    byte buffer[80];
    if (len > 80) len = 80;
    client.read(buffer, len);
    if (printWebData) {
      Serial.write(buffer, len); // show in the serial monitor (slows some boards)
    }
    byteCount = byteCount + len;
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
   
   // do nothing forevermore:
    while (true) {
      delay(1);
    }
  }
}

l'output su monitor seriale che mi viene dato è:

Initialize Ethernet with DHCP:
  DHCP assigned IP 192.168.1.107
connecting to 192.168.1.80...
connection failed

disconnecting.

Ho provato lo script d'esempio del Web Client da cui ho tratto il codice e funziona perfettamente, per cui non è un problema di Hardware della Shield, lo script PHP nemmeno, in quanto l'ho provato da local host è funziona anche quello, davvero non capisco quale possa essere il problema.
Ho attivato APACHE su xampp e l'indirizzo IP del server, ovvero del mio pc,l'ho preso lanciando ipconfig da cmd, quindi davvero non capisco.
ma a seguito della GET devo specificare un path riguardo dove si trova lo script php, oppure basta inserire semplice /nomescript.php... ? Questo perché lo script si trova in htdocs ovviamente.
Scusate se le cose che chiedo risultano banali

lcfmr:
l'output su monitor seriale che mi viene dato è:
Initialize Ethernet with DHCP:
DHCP assigned IP 192.168.1.107
connecting to 192.168.1.80...
connection failed

La connessione fallisce, ma non sappiamo bene perché. Intanto ti consiglio di memorizzare il valore di ritorno della connect() perché ti dà indicazioni del problema:

Returns an int (1,-1,-2,-3,-4) indicating connection status :

SUCCESS 1
TIMED_OUT -1
INVALID_SERVER -2
TRUNCATED -3
INVALID_RESPONSE -4

quindi una cosa del tipo:

  // if you get a connection, report back via serial:
  int retcode = client.connect(server, 80);
  if (retcode) {
    Serial.print("connected to ");
    Serial.println(client.remoteIP());
    // Make a HTTP request:
    client.println("GET /esempio.php?Username=Arduino HTTP/1.1");
    client.println("Host: 192.168.1.80");
    client.println("Connection: close");
    client.println();
    client.println();
  } else {
    // if you didn't get a connection to the server:
    Serial.print("connection failed (");
    Serial.print(retcode);
    Serial.println(")");
  }

A parte questo, non capisco bene, tu dici:

Ho provato lo script d'esempio del Web Client da cui ho tratto il codice e funziona perfettamente, per cui non è un problema di Hardware della Shield

Intendi dire che hai provato l'esempio WebClient.ino della libreria e si connette correttamente (ovviamente dopo aver configurato l'IP del tuo server locale) mentre questo tuo codice no? A me pare praticamente identico, sei proprio sicuro? Posta lo sketch di esempio che hai usato (ossia quello ricavato da WebClient e modificato per il solo IP) e relativo output del serial monitor.

Non è che magari hai un firewall sul tuo Linux (che distro e versione?) che blocca le connessioni esterne (es. iptables)?

ma a seguito della GET devo specificare un path riguardo dove si trova lo script php, oppure basta inserire semplice /nomescript.php... ? Questo perché lo script si trova in htdocs ovviamente.

No, il path è quello che "vedi" anche da browser ossia relativo alla "root" del tuo server web (Apache nel tuo caso). Come ti ho detto, se tu lo provi da browser e funziona, devi solo estrarre quello che devi mettere nella GET seguendo l'esempio che ti avevo indicato.

Perfetto, partiamo con ordine:

questo è il mio sketch modificato a seguito del tuo suggerimento:

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
IPAddress server(192,168,1,80);  // numeric IP for Google (no DNS)
//char server[] = "www.google.com";    // name address for Google (using DNS)

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);
IPAddress myDns(192, 168, 0, 1);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;


unsigned long byteCount = 0;
bool printWebData = true;  // set to false for better speed measurement

void setup() {

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) {
        delay(1); // do nothing, no point running without Ethernet hardware
      }
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip, myDns);
  } else {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.print("connecting to ");
  Serial.print(server);
  Serial.println("...");

  // if you get a connection, report back via serial:
    int retcode = client.connect(server, 80);

   if (retcode) {
    Serial.print("connected to ");
    Serial.println(client.remoteIP());
    // Make a HTTP request:
    client.println("GET /esempio.php?Username=Arduino HTTP/1.1");
    client.println("Host: 192.168.1.80");
    client.println("Connection: close");
    client.println();
    client.println();
  } else {
    // if you didn't get a connection to the server:
    Serial.print("connection failed (");
    Serial.print(retcode);
    Serial.println(")");
  }

}

void loop() {

  int len = client.available();
  if (len > 0) {
    byte buffer[80];
    if (len > 80) len = 80;
    client.read(buffer, len);
    if (printWebData) {
      Serial.write(buffer, len); // show in the serial monitor (slows some boards)
    }
    byteCount = byteCount + len;
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
   
   // do nothing forevermore:
    while (true) {
      delay(1);
    }
  }
}

l'output su monitor seriale che mi viene dato è:

Initialize Ethernet with DHCP:
  DHCP assigned IP 192.168.1.107
connecting to 192.168.1.80...
connection failed (0)

disconnecting.

Lo scrip d'esempio che ho usato è questo:

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
//char server[] = "www.google.com";    // name address for Google (using DNS)

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);
IPAddress myDns(192, 168, 0, 1);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

// Variables to measure the speed
unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true;  // set to false for better speed measurement

void setup() {
  // You can use Ethernet.init(pin) to configure the CS pin
  //Ethernet.init(10);  // Most Arduino shields
  //Ethernet.init(5);   // MKR ETH shield
  //Ethernet.init(0);   // Teensy 2.0
  //Ethernet.init(20);  // Teensy++ 2.0
  //Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
  //Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) {
        delay(1); // do nothing, no point running without Ethernet hardware
      }
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip, myDns);
  } else {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.print("connecting to ");
  Serial.print(server);
  Serial.println("...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.print("connected to ");
    Serial.println(client.remoteIP());
    // Make a HTTP request:
    client.println("GET /search?q=arduino HTTP/1.1");
    client.println("Host: www.google.com");
    client.println("Connection: close");
    client.println();
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
  beginMicros = micros();
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  int len = client.available();
  if (len > 0) {
    byte buffer[80];
    if (len > 80) len = 80;
    client.read(buffer, len);
    if (printWebData) {
      Serial.write(buffer, len); // show in the serial monitor (slows some boards)
    }
    byteCount = byteCount + len;
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    endMicros = micros();
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    Serial.print("Received ");
    Serial.print(byteCount);
    Serial.print(" bytes in ");
    float seconds = (float)(endMicros - beginMicros) / 1000000.0;
    Serial.print(seconds, 4);
    float rate = (float)byteCount / seconds / 1000.0;
    Serial.print(", rate = ");
    Serial.print(rate);
    Serial.print(" kbytes/second");
    Serial.println();

    // do nothing forevermore:
    while (true) {
      delay(1);
    }
  }
}

Ed ho appena notato che effettivamente il server non si disconnette mai, continua a stamparmi cose su monitor seriale, cioè non entra mai nell'

if (!client.connected())

.
Ho catturato con uno screenshoot le prime informazioni stampate perché è impossibile fare copia incolla:

connected to 74.125.232.128
HTTP/1.1 200 OK
Content-Type: text/html; charset=ISO-8859-1
Date: Tue, 31 Mar 2020 12:00:02 GMT
Expires: -1
Cache-Control: private, max-age=0
P3P:CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: IP_JAR=2020-03-31-12; expires=Thu, 30-Apr-2020 12:00:002 GMT; path=/; domain=.google.com; Secure
... 
...

Volevo allegare direttamente qui lo screen, non è possibile hostare immagini sul forum? :frowning:

Non è che magari hai un firewall sul tuo Linux (che distro e versione?) che blocca le connessioni esterne (es. iptables)?

Attualmente sto usando un pc con Windwos 10 come Server, quindi escludo possa essere un problema di firewall, e poi in ogni caso essendo una comunicazione in locale potrebbero comunque esserci problemi di firewall?

lcfmr:
l'output su monitor seriale che mi viene dato è:

Bene, quindi la connect() ritorna zero. Provo ad andare passo-passo così vedi anche tu come operare in questi casi. Per prima cosa vai a vedere la libreria, in particolare "EthernetClient.cpp" (trovi tutto nella cartella "libraries" del tuo IDE) che è il modulo che contiene la connect(), quindi questa:

int EthernetClient::connect(IPAddress ip, uint16_t port)
{
	if (sockindex < MAX_SOCK_NUM) {
		if (Ethernet.socketStatus(sockindex) != SnSR::CLOSED) {
			Ethernet.socketDisconnect(sockindex); // TODO: should we call stop()?
		}
		sockindex = MAX_SOCK_NUM;
	}
#if defined(ESP8266) || defined(ESP32)
	if (ip == IPAddress((uint32_t)0) || ip == IPAddress(0xFFFFFFFFul)) return 0;
#else
	if (ip == IPAddress(0ul) || ip == IPAddress(0xFFFFFFFFul)) return 0;
#endif
	sockindex = Ethernet.socketBegin(SnMR::TCP, 0);
	if (sockindex >= MAX_SOCK_NUM) return 0;
	Ethernet.socketConnect(sockindex, rawIPAddress(ip), port);
	uint32_t start = millis();
	while (1) {
		uint8_t stat = Ethernet.socketStatus(sockindex);
		if (stat == SnSR::ESTABLISHED) return 1;
		if (stat == SnSR::CLOSE_WAIT) return 1;
		if (stat == SnSR::CLOSED) return 0;
		if (millis() - start > _timeout) break;
		delay(1);
	}
	Ethernet.socketClose(sockindex);
	sockindex = MAX_SOCK_NUM;
	return 0;
}

Quando restituisce zero? Quando la connessione viene chiusa dal server (CLOSED) o quando arriva al timeout (col break esce dalla while). Per cui sei in uno di questi due casi.
Passiamo al test che hai fatto con Google:

Ho catturato con uno screenshoot le prime informazioni stampate perché è impossibile fare copia incolla:

Tutto quello che vedi dopo "connected to" è la risposta della pagina di Google, dalle intestazioni http (da HTTP/1.1... fino alla prima riga vuota) e dal corpo della pagina (tutto quello che viene dopo, parecchia roba).

A parte quindi i dettagli del protocollo http, è evidente che con lo stesso codice (ma che punta a Google invece del tuo server) tutto funziona. Quindi il problema non è né di Arduino né del codice, non ti pare?
Quindi è altro. Ossia:

Attualmente sto usando un pc con Windwos 10 come Server, quindi escludo possa essere un problema di firewall, e poi in ogni caso essendo una comunicazione in locale potrebbero comunque esserci problemi di firewall?

Certamente che ci sono, perché non è il firewall del tuo modem router a bloccare quelle connessioni in rete locale, ma il firewall del TUO computer! Il firewall del modem router blocca le connessioni provenienti dall'"esterno" inteso come "fuori dalla tua rete di casa", tu devi aprire sul tuo PC la porta 80 TCP alle connessioni "esterne" (in questo caso l'"esterno" è "qualsiasi sistema diverso dal tuo PC").

Quindi segui QUESTA guida ed apri la porta 80 TCP, poi riprova.

Prima di farlo, però, se vuoi verificare questa cosa ed hai un altro PC in casa, ti basta aprire un prompt di comandi (ovviamente sul tuo PC devi avere attivato Apache su xamp) e digitare il comando:

telnet 192.168.1.80 80

Nota: il secondo "80" è separato da uno spazio ed è la porta TCP dell'http; se ti dice che non trova il comando "telnet" lo puoi attivare andando su Pannello di controllo, "Programmi e Funzionalità", poi "Attivazione o disattivazione funzionalità di Windows", seleziona "Telnet client" e conferma)

Se dopo un po' esce un errore (es. "Impossibile aprire una connessione con l'host"), non puoi connetterti o perché l'host non ha attivo il web server o perché non ha aperto quella porta.

Se invece lo schermo diventa scuro (e quindi dopo che avrai aperto la porta 80) allora sei connesso ed in tal caso digita il comando GET (non preoccuparti se non vedi nulla mentre scrivi, ma scrivilo attentamente perché non puoi "correggere"):

GET / HTTP/1.1

e premi due volte Invio. Vedrai la risposta del server.

il server non si disconnette mai, continua a stamparmi cose su monitor seriale

Questo è normale, fa parte del protocollo HTTP (che ti consiglio nuovamente di studiare un poco). La connessione http che si fa può richiedere o meno la chiusura del canale al termine della risposta, e spesso la connessione viene lasciata aperta perché se il client deve richiedere altri oggetti al server (es. le immagini contenute nella pagina) lo può fare senza dover instaurare una nuova connessione.

Volevo allegare direttamente qui lo screen, non è possibile hostare immagini sul forum?

Certo, salva l'immagine in locale e poi mettila come allegato (devi cliccare su "Attachments and other options" in basso, sotto all'editor).
Ma credo che non serva più in questo caso :slight_smile:

Guarda grazie davvero per il prezioso supporto, purtroppo ora un senso di frustrazione enorme mi accompagna.
Ho fatto tutto quello che mi hai detto, la porta 80 è abilitata con TCP, ho abilitato e provato ad utilizzare telnet da un altro pc ma purtroppo non si riesce a connettere :(, ovviamente apache è attivo e nel dubbio ho ricontrollato l'ip che però è giusto.

Non ti scoraggiare, se è la prima volta che fai cose del genere può capitare, ma non conoscendo bene la tua configurazione non è semplice.

Per cercare quindi di permettere al tuo Arduino di connettersi correttamente, prova a disattivare temporaneamente il firewall di Windows e riprova col telnet. Se così ti connetti allora è qualche altra configurazione di Windows Firewall, devi vedere meglio se hai qualche altra regola che impedisce la connessione e rimuoverla.

Se invece, come credo, non dovesse andare ancora, allora apri il Control Panel di XAMPP e controlla col suo netstat (è il pulsante in alto a destra) le porte, cattura lo schermo e mandalo qui come allegato, e manda pure il file "httpd.conf" che trovi in "C:\xampp\apache\conf".

Ah, prova anche a fare dalla macchina stessa dove hai XAMPP, in un prompt comandi:

telnet localhost 80

e dimmi se così ti connetti.

E alla fine delle prove riattiva il firewall, che è sempre utile avere!

Ah, dimenticavo, ovviamente invece del telnet puoi anche provare ad usare il normalissimo browser richiamando:

http://192.168.1.80/

e vedi se risponde. Oppure prova anche:

http://localhost/

Poi hai guardato il log di Apache (sempre tramite Control Panel di XAMPP) se ti dice qualcosa alla partenza?

Ma mi è anche venuta in mente un'altra cosa... Non è che per caso sul tuo PC hai anche IIS (Internet Information Services, il web server di Microsoft) o IIS Express (la versione per sviluppo web di Visual Studio)?

Alcuni aggiornamenti di Windows 10 a volte attivano/installano il servizio IIS, ed IIS lavorando sulla porta 80 è possibile che impedisca di usare Apache sulla stessa porta. Per cui o disattivi IIS o cambi la porta di Apache.

Per capirlo, clicca sul pulsante start, e digita "Servizi", poi cerca "Servizio Pubblicazione sul Web" e se c'è ed è in stato "In esecuzione" cliccaci col tasto destro e fai "Arresta". Quindi riavvia Apache da ZAMPP e vedi se ti connetti con telnet o col browser: se così funziona allora o imposti su "Manuale" quel servizio se non ti serve, oppure cambi la porta di Apache (io lo farei da httpd.conf ma forse puoi farlo anche dal Control Panel XAMPP).

docdoc:
Ah, dimenticavo, ovviamente invece del telnet puoi anche provare ad usare il normalissimo browser richiamando:

http://192.168.1.80/

e vedi se risponde. Oppure prova anche:

http://localhost/

Poi hai guardato il log di Apache (sempre tramite Control Panel di XAMPP) se ti dice qualcosa alla partenza?

Ma mi è anche venuta in mente un'altra cosa... Non è che per caso sul tuo PC hai anche IIS (Internet Information Services, il web server di Microsoft) o IIS Express (la versione per sviluppo web di Visual Studio)?

Alcuni aggiornamenti di Windows 10 a volte attivano/installano il servizio IIS, ed IIS lavorando sulla porta 80 è possibile che impedisca di usare Apache sulla stessa porta. Per cui o disattivi IIS o cambi la porta di Apache.

Per capirlo, clicca sul pulsante start, e digita "Servizi", poi cerca "Servizio Pubblicazione sul Web" e se c'è ed è in stato "In esecuzione" cliccaci col tasto destro e fai "Arresta". Quindi riavvia Apache da ZAMPP e vedi se ti connetti con telnet o col browser: se così funziona allora o imposti su "Manuale" quel servizio se non ti serve, oppure cambi la porta di Apache (io lo farei da httpd.conf ma forse puoi farlo anche dal Control Panel XAMPP).

Non ho capito l'ordine in cui mi hai consigliato di procedere dal post di prima ma in ogni caso, sapevo del problema di ISS, ma su questo PC non è presente.
Ho lanciato il comando telnet su local host ed è connesso comunque, mi consigli di disattivare i firewall e di riprovare con l'altro pc quindi?

Beh ma non ho capito bene cosa intendi con "ed è connesso comunque": hai fatto "telnet localhost 80" e si è connesso? In ogni caso fai le prove nell'ordine in cui te le ho scritte nei due messaggi, e riportami l'esito di ciascuna, inclusi gli allegati che ti ho chiesto, così cerco di capire meglio cosa hai fatto, cosa hai ottenuto e quindi quale possa essere la tua configurazione.