Pages: [1] 2   Go Down
Author Topic: Problème Ethernet Shield HTTP  (Read 2713 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour à tous,

je dispose d'un Arduino Mega 2560 connecté à un Ethernet Shield.

Je souhaite récupérer quelques informations sur un serveur Web, pour cela je me connecte au serveur avec un client.connect()
puis après l'envoi de la requête GET, je récupère les informations qui m'intéressent avec des client.read().

Seulement voilà, dès la deuxième connexion, en plein milieu de la réception des en-têtes, l'ethernet shield me donne le même caractère en boucle.

Exemple :

HTTP/1.1 200 OK
...
Connection: close
Cacheeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee...

S'agit-il d'un problème de programmation récurrent, ou encore d'un problème avec la librairie Ethernet ?

J'ai tenté de stopper la connexion lors de la réception après un délais trop important, réinitialiser le shield avec un Ethernet.begin et reconnecter pour demander la même page ; le même problème se reproduit sur le même caractère.

Y a-t-il besoin de vider un buffer de réception ?


Merci.
Logged

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Peut-être que cela peut t'aider :

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1282763701/all
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Merci pour cette réponse rapide.

J'avais déjà regardé ce topic, je suis quasiment sûr de ne pas avoir de problème de mémoire vive car en utilisant une fonction de test de ram disponible, je vois que j'ai à chaque connexion quasiment 5ko.

Normalement je n'ai pas de problème de synchronisation avec le serveur car j'utilise une boucle d'attente de réponse.
Pas de problème non plus de la connexion précédente mal fermée, j'utilise HTTP/1.0 (pas de connexion persistante) et je vérifie à chaque connexion que la connexion précédente est bien fermée.

Enfin en gros je sèche...

voilà le code de ma fonction de connexion qui envoie la requête et lit les en-têtes de manière à laisser l'objet client prêt à lire le contenu de la page :

Code:
/* Connexion et envoi requete GET */
/* Retour : true si erreur */
bool connexion(char *adresse_connexion)
{
        Serial.print(" libre : ");
        Serial.println(memoryTest());
        deconnexionClient();
       
        if (client.connect())
        {
                delay(100);
                client.print("GET /");
                client.print(adresse_connexion);
                client.println(" HTTP/1.0");
                client.println();
               
                //attente serveur
                Serial.print("att.");
                unsigned long debut_tentative = millis();
                while (client.available() == 0)
                {
                        delay(10);
                        if (!client.connected())
                        {
                        erreur(30);
                        client.stop();
                        return true;
                        }
else if ((millis() - debut_tentative) > TIMEOUT)
{
erreur(35);
return true;
}
                }
                Serial.println("ok");
               
                //passage entetes
                char carac;
                bool clrf = false;
                debut_tentative = millis();
                Serial.println("Entetes...");
                while (true)
                {
                if ((millis() - debut_tentative) > LONG_TIMEOUT)
{
erreur(39);
                                reinitShield();
return true;
}
               
                        if (client.available())
                {
        carac = client.read();
                                Serial.print(carac);
        if (carac == '\n')
        {
        //si deux retours à la ligne de suite lus, entetes passés
        if (clrf) break;
        else clrf = true;
        }
        else if (carac != '\r') clrf = false;
                }
                        else if ((millis() - debut_tentative) > TIMEOUT)
{
erreur(36);
return true;
}
                else if (!client.connected())
                {
                erreur(30);
                return true;
                }
                }
                Serial.println("ok");
                return false;
        }
        else
        {
                erreur(36);
                return true;
        }
}

//s'assurer que la connexion est fermée
void deconnexionClient()
{
        while (client.connected()) client.flush();
        client.stop();
}

//réinitialisation de l'ethernet shield
void reinitShield()
{
        client.stop();
        Serial.println("reinit reseau");
        delay(1000);
        Ethernet.begin(mac, ip, gateway, subnet);
        delay(1000);
        Serial.println("ok");
}

(je numérote les erreurs pour économiser de la mémoire)
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bon, j'ai rajouté des delay() un peu partout, j'ai maintenant 4 ou 5 connexions qui s'effectuent correctement avant de planter et j'ai des erreurs de déconnexion (erreur 30 pendant l'attente du serveur).

Une idée ? je suppose que les délais améliorent les choses pour les tampons de réception mais je ne vais pas mettre un délai de 2 seconde à chaque fois que j'utilise l'objet client...
Logged

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 4
Posts: 419
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Salut,

si je peux me permettre, ça me parait bien tordu comme code  smiley-confuse
Il n'y a pas moyen de faire plus simple ? Par exemple en récupérant la réponse dans un buffer, puis seulement après l'analyser pour trouver l'octet de début des données intéressantes.
J'ai beau essayer de comprendre le bout de code que tu nous fournis, ça reste trop obscure.

Qu'as-tu comme serveur en face ?
Peux-tu nous donner un exemple de ce que le serveur renvoi comme data en réponse de la requête GET ? (en utilisant un sniffer de datagramme comme wireshark par exemple)

Gromain
« Last Edit: June 14, 2011, 06:23:43 am by Gromain59 » Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Pour être tordu ça l'est c'est vrai...

À vrai dire c'est le troisième bout de code servant à faire la même chose que j'écris, mais de toute évidence dans chacun de mes codes il y a le même genre d'erreur.

Le serveur auquel j'accède avec la requête GET est un Apache.

Voici une copie des Serial.print lorsque ça marche :

Code:
libre : 4862
att.ok
Entetes...!HTTP/1.1 200 OK
Date: Tue, 14 Jun 2011 12:37:07 GMT
Server: Apache/2.2.17 (Ubuntu)
X-Powered-By: PHP/5.3.5-1ubuntu7.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 20
Connection: close
Content-Type: text/html

Et en voilà une autre quand ça plante :
Code:
libre : 5057
att.Erreur 30
 libre : 5057
att.Erreur 30
 libre : 5057
att.Erreur 30
 libre : 5057
att.Erreur 30
 libre : 5057
att.Erreur 30
 libre : 5057
att.ok
Entetes...!HTTP/1.1 200 OK
Date: Tue, 14 Jun 2011 12:37:54 GMT
Server: Apache/2.2.17 (Ubuntu)
X-Powered-By: PHP/5.3.5-1ubuntu7.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cachee-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-(plein de "-e-")Erreur 39
reinit reseau
ok
 libre : 5057
att.ok
Entetes...!HTTP/1.1 200 OK
Date: Tue, 14 Jun 2011 12:38:18 GMT
Server: Apache/2.2.17 (Ubuntu)
X-Powered-By: PHP/5.3.5-1ubuntu7.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cachee-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e-e...Erreur 39
reinit reseau
ok

Et le résultat est complètement aléatoire (varie entre les erreur de déconnexion et les caractères en boucle, et parfois une requête qui passe correctement) dès que ça a planté.

Sinon je me demande aussi d'où sort le point d'exclamation avant la réponse (!HTTP/1.1 200 OK)

Avec wireshark je vois des belles requetes HTTP telle que

GET /mapage HTTP/1.0
[
ack
continuations or non-http,
parfois TCP port reused
            TCP windows update
            1028 > http [RST]
]
HTTP/1.1 200 ok (text/html)

Mais quand ça se met à planter le module envoie un peu n'importe quoi :

GET /mapageET /mapageGET /mapage HTTP/1.0\r\n

Et là le serveur renvoie des 400 Bad Request.

Je vais remettre un autre code pour retrouver les erreurs sur des fonctions plus simplement codées...

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je retire ma question pour le point d'exclamation avant le HTTP, j'avais mis le serial.print() avant le client.read() (et en plus j'avais corrigé cette erreur en postant le code dans le forum smiley-roll)...

Et je précise que si j'utilise ce système de lecture des données après la fonction connexion c'est pour lire ligne par ligne des pages Web éventuellement grosse sans allouer un buffer de 1000 octets ; cela dit je crois que je vais le faire tout de même puisque j'ai suffisamment de ram disponible.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Après actualisation de la fonction pour enregistrer le contenu de la réponse dans un buffer, j'ai 4 connexions qui se passent sans problème puis j'ai à nouveau le problème de la boucle sur les deux caracères "-e" de l'entete Cache-control (souvent précédé d'une erreur de déconnexion pendant l'attente du serveur).

Avec wireshark, la requête get semble bonne la plupart du temps, mais quelque fois le module envoie des requête erronées (caractères spéciaux qui apparaissent).

La première erreur de boucle est souvent précédée d'un "DUP ACK" de la part de l'aduino.


Logged

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

essaye avec ça :

Code:
/*
  Web client
 
 This sketch connects to a website (http://www.google.com)
 using an Arduino Wiznet Ethernet shield.
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 
 created 18 Dec 2009
 by David A. Mellis
 
 */


#include <Ethernet.h>
#include <PString.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = {
  192,168,0,177 };
byte server[] = { 217,107,214,2 }; // jfsgeneva.com

// 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):
Client client(server, 80);
String stringOne = "";
long echec=0;

void setup() {
  // start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // start the serial library:
  Serial.begin(9600);
  // give the Ethernet shield a second to initialize:
  delay(1000);
  // Serial.println("connecting...");

  // if you get a connection, report back via serial:

}


void loop(){
 

  Serial.println("connecting...");
  if (client.connect()) {
   // client.flush();
   // Serial.flush();
    Serial.println("connected");
    // Make a HTTP request:
    client.print("GET http://monsite.com/test/?turlututu");
    client.println(" HTTP/1.1");
    client.print("Host: monsite.com\n");
    client.print("Referer: http://monsite.com\n\n");
    client.println();
    delay(200);
  }
  else if (!client.connected()){
    // if you didn't get a connection to the server:
    Serial.println("connection failed");

  }


  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()!=0) {
    int b=client.available();
    for (int a=0; a < b+1000;a++){
      char c = client.read();
     // Serial.print(c);
     
     String stringOne += c;
     // Serial.flush();
     

    }
    Serial.println(String stringOne);
   // client.flush();
    Serial.flush();
    //client.stop();
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    Serial.println();
    Serial.println();
    client.flush();
    Serial.flush();
    client.stop();

    // do nothing forevermore:
    // for(;;)
    //   ;
  }
  delay(2000);
}


Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

France
Offline Offline
Faraday Member
**
Karma: 55
Posts: 5347
Arduino Hacker
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour, Jean-Francois je me permet d'ajouter mon grain de sel ^^"
Dans le code que tu fourni il faut ajouter : #include <SPI.h>
Et remplacer :
Code:
     String stringOne += c;
    Serial.println(String stringOne);
par :
Code:
     stringOne += c;
    Serial.println(stringOne);

Voila c'était mon grain de sel du jour ^^"
Sinon le webclient sans pstring (parce que les strings c'est le mal (enfin uniquement en prog ^^"") ) :
Code:
#include <SPI.h>
#include <Ethernet.h>

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,1,177 };
byte server[] = { 209,85,147,103 }; // Google.com

Client client(server, 80);

void setup() {
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  delay(1000);
  Serial.println("connecting...");

  if (client.connect()) {
    Serial.println("connected");
    client.println("GET /search?q=arduino HTTP/1.0");
    client.println();
  }
  else {
    Serial.println("connection failed");
  }
}

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

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    for(;;);
  }

Logged

Des news, des tuto et plein de bonne chose sur http://skyduino.wordpress.com !

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour, Jean-Francois je me permet d'ajouter mon grain de sel ^^"

Sans soucis ... même pas mal   smiley-lol
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonmatin à vous,

j'ai essayé votre code, pas de problème, je l'ai modifié pour récupérer la page en boucle, pas de problème non plus. j'ai donc repris mon code après l'avoir vidé (j'avais 20ko d'autres choses) pour ne laisser que ma fonction de récupération HTTP avec un appel dans loop(), ça fonctionne...

Pourtant dans le reste du code je ne touche pas au réseau, étrange.
Peut-être est-ce le LCD qui est en route ? Mais il ne prend pas de ports utilisées par le shield normalement, il est connecté sur les pins 2, 3, 4, 5, 8 et 9.

Petite précision : si je remet le code qui plante dans l'arduino, que j'attends le premier plantage après 4 ou 5 connexions, et qu'après avoir planté je reprogramme l'arduino avec votre code, cela plante toujours, même avec un reset, il faut que je débranche et rebranche l'usb pour que ça reprenne correctement.
Logged

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 4
Posts: 419
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Peut-être est-ce le LCD qui est en route ?
C'est la première fois que tu mentionnes l'utilisation d'un LCD non ? C'est le genre de détails qui peuvent expliquer ton problème pourtant...

Quote
cela plante toujours, même avec un reset, il faut que je débranche et rebranche l'usb pour que ça reprenne correctement.
Si tu es obligé de couper c'est qu'il y a certainement corruption de données. Probablement coté wiznet. J'ai le cas lorsque son buffer (circulaire) de réception est saturé. Donc soit tu ne vides pas assez vite/souvent son buffer, soit tu reçoit de trop gros paquets d'un coup. Le buffer de réception est configuré à 2ko par défaut (8 ko partagés entre les 4 sockets disponibles du wiznet).
Vois pour charger des pages plus light, décharger le buffer au plus vite (pas de delay() qui neutralise l'arduino trop longtemps !) ou, en dernier recours, augmenter la taille du buffer au détriment des autres sockets.

Gromain
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bon, même avec le code simplifié je fini par planter (cette fois après quelques minutes de réussite pour une page par seconde tout de même).
Je dois pouvoir laisser l'arduino fonctionner sans avoir à le redémarrer manuellement, si encore je pouvais réinitialiser totalement le W5100 quand ça plante pour que ça reprenne correctement, ça me conviendrait, mais je ne vois pas.

Je viens de regarder du côté de wireshark,  les requêtes GET sont toujours erronées lorsque ça plante, mais cela signifie que le buffer d'émission dépasse et pas celui de reception ?

Est-il possible que le buffer de réception déborde sur celui d'émission ? je croyais qu'il s'agissait de buffers circulaires.

Le premier plantage cette fois commence toujours par une déconnexion pendant l'attente de réponse.
Logged

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 4
Posts: 419
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
les requêtes GET sont toujours erronées lorsque ça plante, mais cela signifie que le buffer d'émission dépasse et pas celui de reception ?
en émission, il peut probable que tu satures le buffer sur un simple GET

Quote
Est-il possible que le buffer de réception déborde sur celui d'émission ?
Je dirais que non.

Quote
Le premier plantage cette fois commence toujours par une déconnexion pendant l'attente de réponse.
selon moi, et surtout selon TCP/IP, il faut systématiquement faire une connexion avant l'envoi de la requête, puis fermer celle-ci à la fin de la réponse. Si j'ai bien compris, tu ouvres la connexion au niveau du setup, puis tu fais tes requêtes. Ça pourrait expliquer pourquoi ça merdouille quand tu subis une déconnexion ?

Le serveur est chez toi ?

Gromain
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pages: [1] 2   Go Up
Jump to: