Ethernet Shield V3 - still freezing (4 sockets limit? client.stop() problem?)

Hello, I'm new here (sorry, I didn't present myself yet.. maybe later..).

Setup:
Arduino UNO v.3 (IDE 1.0.3) + Ethenet Shield v.3 - [programmed as simple client that reads a txt file on a webserver]

Problem:
It's 2012 2013 :slight_smile: and I still see my shield (programmed as client) functioning well but then freezing after some time while reading a txt file from a web server (GET method).
It seems that it is related to the 4 sockets limit and the client.stop() function not working, so that sockets are not closed poperly.

I tried to follow all the several methods described in the forum, but they did not seem to work:

  • disable SD pin 4 (HIGH)
  • delays everywhere
  • flushing everywhere
  • checking client.connected();
  • checking client.status();
  • relaunching Ethernet.begin(mac) ..

These are old 2009-2011 advices, some of them are outdated or already included in the Libraries (SurferTim patch, ...).

So my question(s):
What is the state or the art? Is the shield working for you?
Is the client.stop() - socket disconnession solved or still an issue?

Thanks to all. Maybe I'll post the code also..

So my question(s):
What is the state or the art? Is the shield working for you?
Is the client.stop() - socket disconnession solved or still an issue?

Thanks to all. Maybe I'll post the code also..

I think the w5200 is the state of the art, but not widely available yet.
The ethernet shield is working good for me.
The socket disconnect is not an issue with my code.

Post your code. Here is mine:
http://playground.arduino.cc/Code/WebClient

As a server I set the refresh rate in the below code to 0 and let it run with IE requesting the updates. It made 500,000+ refreshes without hanging, so the serving side is stable with simple code.

// zoomkat's meta refresh data iframe test page 12/24/12
// use http://192.168.1.102:84 in your brouser for main page
// http://192.168.1.102:84/data static data page
// http://192.168.1.102:84/datastart meta refresh data page
// for use with W5100 based ethernet shields
// set the refresh rate to 0 for fastest update
// use STOP for single data updates

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // arduino ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
unsigned long int x=0; //set refresh counter to 0
String readString; 

//////////////////////

void setup(){
  Serial.begin(9600);
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();
  Serial.println("meta refresh data frame test"); // so I can keep track of what is loaded
}

void loop(){
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
         if (readString.length() < 100) {
          readString += c; 
         } 
        //check if HTTP request has ended
        if (c == '\n') {

          //check get atring received
          Serial.println(readString);

          //output HTML data header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          //generate data page
          if(readString.indexOf("data") >0) {  //checks for "data" page
            x=x+1; //page upload counter
            client.print("<HTML><HEAD>");
            //meta-refresh page every 1 seconds if "datastart" page
            if(readString.indexOf("datastart") >0) client.print("<meta http-equiv='refresh' content='0'>"); 
            client.print("<title>Zoomkat's meta-refresh test</title></head><BODY>
");
            client.print("page refresh number ");
            client.print(x); //current refresh count
            client.print("

");
              //output the value of each analog input pin
             for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
             client.print("analog input ");
             client.print(analogChannel);
             client.print(" is ");
             client.print(analogRead(analogChannel));
             client.print("
");
             }
            client.print("</BODY></HTML>");
           }
          //generate main page with iframe
          else
          {
            client.print("<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>");
            client.print("Zoomkat's Arduino frame meta refresh test 12/24/12");
            client.print("

Arduino analog input data frame:
");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/datastart' target='DataBox' title=''yy''>REFRESH</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/data' target='DataBox' title=''xx''>STOP</a>
");
            client.print("<iframe src='http://192.168.1.102:84/data' width='35%' height='250' name='DataBox'>");
            client.print("</iframe>
</HTML>");
          }
          delay(1);
          //stopping client
          client.stop();
          //clearing string for next read
          readString="";
        }
      }
    }
  }
}

Just a quick update:
Many thanks for your examples. I'm using them to debug more and trying new things.
My general impression for now is that the shields functions, but freezes often when reading data (a text file) from the server (client.read()).
I'll post more later.. bye!

My general impression for now is that the shields functions, but freezes often when reading data (a text file) from the server (client.read()).

Mine functions great and doesn't freeze. Sounds like zoomkat's doesn't freeze either. Must be your code.

kev8:
Maybe I'll post the code also..

Maybe we can help if you post your code.

kev8:
Just a quick update:
Many thanks for your examples. I'm using them to debug more and trying new things.
My general impression for now is that the shields functions, but freezes often when reading data (a text file) from the server (client.read()).
I'll post more later.. bye!

Are you sure the webserver is always available when Arduino tries to read that file? Somebody here on the forum wrote that the method "connect" of the "EthernetClient" class contains a loop of 10 seconds to retry connecting. If the webserver doesn't respond, Arduino hangs. That guy solved the issue by making Arduino act like a server. It waits for a command from the webserver and only then it connects to the webserver (this way Arduino knows the webserver is online).

If the webserver doesn't respond, Arduino hangs.

No, the Arduino waits for the server to respond. It tries 5 times to establish the connection, then returns false if no connection could be established. You can shorten that time by editing the ethernet library files and setting the retry value to less than 5. This is part of the fault tolerance built into the internet.

You can't force it to make a connection that cannot be established. You can only wait a shorter period to determine it failed.

This is the code, sorry it's not very elegant and can be shortened a lot.

Basically, I took the code from http://arduino.cc/en/Tutorial/WebClientRepeating.
Then I perform 2 GET:

  1. the first send sensors reading
  2. the second reads a TXT file containing 2 values for switching on/off 2 leds. I took the method here Search Results for “client” – bildr.org and improved the readPage() function with SurferTim code.
    TXT file is a string like <01> (= 4 chars). Each number represents the LED status (0 or 1).
    The < and > are used to locate and extract the values, because the answer from server is about 120 chars (contains also headers).
// ---------------- IMPORT ------------------------------------
#include <SPI.h>
#include <Ethernet.h>

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

	// variables used by millis 
unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000;   // time to wait before repeating connections

	// variables for connection
char serverName[] = "myserver.example.org";		
EthernetClient client;


	// GET #2
String readValue = "";						   // String to store the readPage() function result

	// variables for sensors
const int tempPin = A0;						   // pin where temp sensors is connected
const int lightPin = A1;					   // pin where light sensor (photoresistor) is connected
const int ledPinR = 6;						   // pin of RED led (LED 1)
const int ledPinW = 2;						   // pinf of WHITE led (LED 2)

int tempRead = 0;                              // value read by temperature sensor (0-1023)
float voltage = 0.0;						   // voltage of the temp sensor
float temp = 0.0;							   // calculated value of the temperature (degrees °C)
int light = 0;								   // value read by light sensor
int LED1 = 0;								   // value to assign to LED 1
int LED2 = 0;								   // value to assign to LED 2

	

// -----------------SETUP --------------------------------------------
void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
  
  pinMode (4, OUTPUT);                  //disable SD card slot on ethernet shield
  digitalWrite (4, HIGH);
  pinMode (10, OUTPUT);                  //explicity enable ethernet
  digitalWrite (10, LOW);
  
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;}
 
  // give the Ethernet shield 1 seconds to initialize, then write debug info:
  delay(1000);
  Serial.print("Ethernet begins.. ");
  Serial.println(Ethernet.localIP());
  
  // initializes LEDs
  pinMode(ledPinR, OUTPUT);
  pinMode(ledPinW, OUTPUT);
  digitalWrite(ledPinR, LOW);
  digitalWrite(ledPinW, LOW);
}

// -----------------------------LOOP---------------------
void loop() {

// HTTP REQUEST  
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {

  // Read and calculate temp
      tempRead = analogRead(tempPin);
      voltage = (tempRead/1024.0) * 5.0;
      temp = ((voltage - 0.5) * 100.0);
  // Read Light
      light = analogRead(lightPin);
      
// -------------------------- GET #1 -----------------------------------------------------
// --------------------------(sends sensors and errors status to server) -----------------
// ---------------------------------------------------------------------------------------

  if (client.connect(serverName, 80)) {
    
    Serial.println("Connected - GET #1");
  
    client.print("GET /sensors.php?temp=");client.print(temp); 			
    client.print("&light=");client.print(light); 			
    client.println(" HTTP/1.1");							
    
    client.println("Host: myserver.example.org"); 									
    client.println("Connection: close");					
    client.println();										
    client.stop();
    delay(50);

    Serial.println("GET #1 - disconnecting.");
    } else {
    // if you didn't get a connection to the server:
    Serial.println("GET #1 - connection failed");
	}
//  ------------------------- End of GET #1
//
//      
// -------------------------- GET #2 --------------------------------------------------
// -------------------------- (reads the values to be assigned to the LEDs ------------    
// ------------------------------------------------------------------------------------
   
    if (client.connect(serverName, 80)) {
    
    Serial.println("Connected - GET #2");
	
    client.println("GET /led.txt HTTP/1.1");					
    client.println("Host: myserver.example.org"); 									
    client.println("Connection: close");					
    client.println();										
    client.stop();
    delay(50);
 
	// read the TXT file
    readValue = readPage();						// Call to readPage(): get the values extracted from led.txt file
	
	// assign the LEDs values
		LED1 = readValue[0]-'0';
		LED2 = readValue[1]-'0';
		digitalWrite(ledPinR,LED1);
		digitalWrite(ledPinW,LED2);
	
  } else {
    // if you didn't get a connection to the server:
    Serial.println("GET #2 - connection failed");
    client.stop();
  }
// ------------------------------- End of GET #2 cycle

// note the time that the connection was made:
  lastConnectionTime = millis();
  delay(1000);
// 
// store the state of the connection for next time through
// the loop:
  lastConnected = client.connected();

  } // Close HTTP REQUEST
} // Close void LOOP


// ----------------- FUNCTIONS -----------------------------

String readPage(){
// This function
// 1. read a TXT file in the form "<xy>" and 
// 2. extract xy and return them (xy can be "00", "01", "10" or "11") 
// 3. or return an error code (example "88") in case reads NULL values

// connectLoop controls the hardware fail timeout
  String inString;
  int connectLoop = 0;
  int stringPos = 0;
  
  Serial.println("Read starting...");
  while(client.connected())
  {
    while(client.available())
    {
      char inChar = client.read();
      delay(1);
      inString = inString + inChar;
      // set connectLoop to zero if a packet arrives
      connectLoop = 0;
    }

    connectLoop++;

    // if more than 10000 milliseconds since the last packet
    if(connectLoop > 10000)
    {
      // then close the connection from this end.
      Serial.println();
      Serial.println("Timeout");
      client.stop();
    }
    // this is a delay for the connectLoop timing
    delay(1);
  }

  Serial.println();
  Serial.println("Read finished.");
  // close client
  client.stop();
  delay (1);
  
  // extract and return valid LED values ("00", "01", "10" or "11") or "Error"
  if (inString.length() != 0){ 		// if inString is not null
  int a = inString.indexOf('<');	// find the position of "<"
  int b = inString.indexOf('>');	// find the position of ">"
  String extracted = inString.substring(a+1,b); // extract the text between "<" and ">"
  delay(1000);

  return extracted;     			// return valid values
  } else {return "88"}                     // return some error code
}

You are not reading the response from the server. That will cause the fail you describe.

    client.print("GET /sensors.php?temp=");client.print(temp); 			
    client.print("&light=");client.print(light); 			
    client.println(" HTTP/1.1");							
    
    client.println("Host: myserver.example.org"); 									
    client.println("Connection: close");					
    client.println();										
    // this will cause problems
    client.stop();
    delay(50);

From my testing, if any characters sent from the server end up in the rx buffer before the connection gets the client.stop(), the connection will not close properly and the socket is no longer available. Three more like that and there will be no sockets available.

Uh, his is a good point.. and a stupid error due to first time programming for HTTP communication!
I was sure that since I was pushing some variables, the server did not have to answer.. instead the GET method requires an answer in any case.
So, adding the reading of the answer is better.. fewer or no errors.

Sometimes (some hours) it still stops working, but I think it is related to some out-of-memory issue (my real code is about 20K.. there are a lot of debugging checks and Serial.prints). I'll try to reduce it and to increase the delay between two server requests and see if the code remains stable for some days..

Thank you Surfer and other people, it was an honor to have prompt answers from all of you!
(.. and Happy New Year)