Go Down

Topic: Web server refresh problem (Read 9240 times) previous topic - next topic

lotus135

Aug 13, 2015, 06:20 pm Last Edit: Aug 13, 2015, 11:17 pm by Nick Gammon
I have the following sketch, working fine but whenever  a button is clicked the page take long time to load since sketch has many button.

I need action immediately without referesh by using sd card webserver, or splitting the sketch into to groups

please help me.

Code: [Select]
#include <SPI.h>
#include <Ethernet.h>

EthernetServer server(80);// Server port

const byte BIT0Pin = 2;// Select pin for 2^0 BIT
const byte BIT1Pin = 3;// Select pin for 2^1 BIT
const byte BIT2Pin = 4;// Select pin for 2^2 BIT
const byte BIT3Pin = 5;// Select pin for 2^3 BIT
const byte BIT4Pin = 6;// Select pin for 2^4 BIT
const byte BIT5Pin = 7;// Select pin for 2^5 BIT

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 0, 200 }; // ip in lan
byte gateway[] = { 192, 168, 0, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask


String readString;

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


void setup()

{
  delay(10);// Delay for Ethernet shield initialization (Arduino has 65mS Power Up delay and W5100 reset logic has 280mS)
  pinMode(BIT0Pin, OUTPUT);// Define pin for  BIT0 as Output
  pinMode(BIT1Pin, OUTPUT);// Define pin for  BIT1 as Output
  pinMode(BIT2Pin, OUTPUT);// Define pin for  BIT2 as Output
  pinMode(BIT3Pin, OUTPUT);// Define pin for  BIT3 as Output
  pinMode(BIT4Pin, OUTPUT);// Define pin for  BIT4 as Output
  pinMode(BIT5Pin, OUTPUT);// Define pin for  BIT5 as Output
  Serial.begin(9600);// Initialize serial communications at 9600 bps
  Serial.println(F("TEST"));// Display Arduino title
  Ethernet.begin(mac, ip, gateway, subnet);// Start Ethernet
  server.begin();
  Serial.print(F("Ethernet Shield initialized. Local IP address is:"));
  Serial.println(Ethernet.localIP());// Print Server IP address
}

void loop()

{
  EthernetClient client = server.available();// Create a client connection
  if (client == true)
  {
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();// Read char by char HTTP request
        if (readString.length() < 100)
        {
          readString = readString + c;// Store characters to string
        }

        //if HTTP request has ended
        if (c == '\n') {
          ///////////////
          Serial.println(readString); //print to serial monitor for debuging
          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: text/html");
          client.println();

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("</HEAD>");
          client.println("<BODY>");
          client.println("<BODY>");
          client.println(F("<body bgcolor='Turquoise'>"));
          client.println(F("<h1><b><center>GAS TURBINE E CONTROL PANEL</b></h2><font size=5>"));
          //client.println(F("<hr/><p> Click the Buttons to turn On and OFF <p/><hr/><br/><br/><br/>"));
          client.print(F("<input type=button value=OPERATION style=position:absolute;left:976px;top:110px;width:150px;height:30px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?off3579'>&nbsp;&nbsp;"));
          client.print(F("<input type=button value=OFF style=position:relative;left:840px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?OFF'>"));
          client.print(F("<input type=button value='CRANK' style=position:relative;left:850px;top:85px;width:85px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?CRK'>"));
          client.print(F("<input type=button value=FIRE style=position:relative;left:860px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?FIR'>"));
          client.print(F("<input type=button value=AUTO style=position:relative;left:870px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?AUT'>"));
          client.print(F("<input type=button value=REM style=position:relative;left:880px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?REM'>"));
          client.print(F("<input type=button value=LOAD style=position:absolute;left:975px;top:230px;width:150px;height:30px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?off3579'>&nbsp;&nbsp;"));
          client.print(F("<input type=button value=PRESEL style=position:relative;left:540px;top:205px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?PRS'>"));
          client.print(F("<input type=button value=BASE style=position:relative;left:560px;top:205px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?BAS'>"));
          client.print(F("<input type=button value=PEAK style=position:relative;left:580px;top:205px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?PEK'><br>"));
          client.println("<br />");
          client.println("<br />");
          client.println("</BODY>");
          client.println("</HTML>");
          delay(1);
          //stopping client
          client.stop();

          ///////////////////// control arduino pin
          if (readString.indexOf("/?OFF") > 0)
          {
            digitalWrite(BIT0Pin, HIGH);   // set the LED on
            digitalWrite(BIT2Pin, HIGH);   // set the LED on
            digitalWrite(BIT3Pin, HIGH);   // set the LED on
            digitalWrite(BIT5Pin, HIGH);   // set the LED on
            delay(500);              // wait for a second
            digitalWrite(BIT0Pin, LOW);   // set the LED on
            digitalWrite(BIT2Pin, LOW);   // set the LED on
            digitalWrite(BIT3Pin, LOW);   // set the LED on
            digitalWrite(BIT5Pin, LOW);   // set the LED on
            delay(0);              // wait for a second

          }
          readString = "";// Clearing string for next read
        }// End of line reached
      }// End of client available
    }// End of client connected
  }// End of client connection
}// End of loop


Moderator edit: [code] ... [/code] tags added. (Nick Gammon)

SurferTim

You are sending all that stuff one character per packet. The client.print and client.println function calls combined with the F() macro causes that. Makes the web page download very slow.

SurferTim

Take the F() macro out.

This is what I use. You can increase or decrease the size of tBuf to match your requirements.
Code: [Select]
  char tBuf[64];

  strcpy_P(tBuf,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html"));
  strcat_P(tBuf,PSTR("\r\nConnection: close\r\n\r\n"));
  client.write(tBuf);

jurs

#3
Aug 13, 2015, 08:26 pm Last Edit: Aug 13, 2015, 09:07 pm by jurs
Thks, any solution to fix
I think your code has several problems (and the F() macro is not really a big problem):
- client.stop() is not placed correctly
- you send your page, even if it is not the requested file
- your code thinks that a client request ends after the first '\n' in the request

I'd better look up the complete request-->response logic in the code.

Besides of that you create invalid HTML.
What's that:
Code: [Select]

  client.println("<BODY>");
  client.println("<BODY>");
  client.println(F("<body bgcolor='Turquoise'>"));

Three consecutive body-tags in a row, two without parameters, one with bgcolor parameter?

SurferTim

The F() macro is a big problem if speed is the problem. A 48 byte header to send one byte is a waste of time and network resources.


jurs

This is my complete code. please find attachment
Oh, I see.

You are talking about a slow code that is actually NOT the same code you posted initially.

The actual code is many times as big as the code you posted initially.

In that case I agree with "SurferTim": When sending many kilobytes of HTML, then the F-macro may lead to significant loading time of your page.

zoomkat

One approach for faster control might be to not refresh the main page after the initial load.


Code: [Select]

//zoomkat 5-30-15
//simple button GET with iframe code
//open serial monitor to see what the arduino receives
//use the ' instead of " in html ilnes
//address will look like http://192.168.1.102:84/ when submited
//for use with W5100 based ethernet shields

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

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //ethernet shield 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

String readString;

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

void setup(){

  pinMode(4, OUTPUT); //pin selected to control
  pinMode(5, OUTPUT); //pin selected to control
  pinMode(6, OUTPUT); //pin selected to control
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();

  //enable serial data print
  Serial.begin(9600);
  Serial.println("multibutton server test 5-30-15"); // so I can keep track of what is loaded
}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string
          readString += c;
          //Serial.print(c);
        }

        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging

            //now output HTML data header
          if(readString.indexOf('?') >=0) { //don't send new page
            client.println("HTTP/1.1 204 Zoomkat\r\n\r\n");
          }
          else {
            client.println("HTTP/1.1 200 OK"); //send new page
            client.println("Content-Type: text/html");
            client.println();

            client.println("<HTML>");
            client.println("<HEAD>");
            client.println("<TITLE>Arduino GET test page</TITLE>");
            client.println("</HEAD>");
            client.println("<BODY>");

            client.println("<H1>Zoomkat's simple Arduino button</H1>");


            client.println("<a href='/?on4' target='inlineframe'>ON 4</a>");
            client.println("<a href='/?off4' target='inlineframe'>OFF 4</a>");

            client.println("<a href='/?on5' target='inlineframe'>ON 5</a>");
            client.println("<a href='/?off5' target='inlineframe'>OFF 5</a>");

            client.println("<a href='/?on6' target='inlineframe'>ON 6</a>");
            client.println("<a href='/?off6' target='inlineframe'>OFF 6</a>");

            client.println("<IFRAME name=inlineframe style='display:none'>");         
            client.println("</IFRAME>");

            client.println("</BODY>");
            client.println("</HTML>");
          }

          delay(1);
          //stopping client
          client.stop();

          ///////////////////// control arduino pin
          if(readString.indexOf("on4") >0)//checks for on4
          {
            digitalWrite(4, HIGH);    // set pin 4 high
            Serial.println("Led 4 On");
          }
          if(readString.indexOf("off4") >0)//checks for off4
          {
            digitalWrite(4, LOW);    // set pin 4 low
            Serial.println("Led 4 Off");
          }
          if(readString.indexOf("on5") >0)//checks for on5
          {
            digitalWrite(5, HIGH);    // set pin 5 high
            Serial.println("Led 5 On");
          }
          if(readString.indexOf("off5") >0)//checks for off5
          {
            digitalWrite(5, LOW);    // set pin 5 low
            Serial.println("Led 5 Off");
          }         
          if(readString.indexOf("on6") >0)//checks for on6
          {
            digitalWrite(6, HIGH);    // set pin 6 high
            Serial.println("Led 6 On");
          }
          if(readString.indexOf("off6") >0)//checks for off6
          {
            digitalWrite(6, LOW);    // set pin 6 low
            Serial.println("Led 6 Off");
          }
          //clearing string for next read
          readString="";
        }
      }
    }
  }
}


Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

nickgammon

#7
Aug 14, 2015, 12:45 am Last Edit: Aug 14, 2015, 12:50 am by Nick Gammon
SurferTim is correct, the F() macro slows things down. I measured 0.75 seconds to send your page with it there, and after the modifications below, it was only 0.16 seconds.

The simplest work-around is to buffer the F() writes. After all, you are usually doing a lot in a row.

I wrote a library for a web server recently. It is described here: Tiny web server for Arduino or similar.

Amongst other things, it greatly simplifies getting back GET and POST parameters from the web page.

I amended it an hour ago to buffer the writes, resulting in the speed improvement I mentioned. You don't need to make any code changes, except to flush the final buffer at the end.

The library can be downloaded from: https://github.com/nickgammon/HTTPserver

I amended your code to use this library, as below:

Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <HTTPserver.h>


// Enter a MAC address and IP address for your controller below.
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// The IP address will be dependent on your local network:
byte ip[] = {  192, 168, 0, 200 };

// the router's gateway address:
byte gateway[] = { 192, 168, 0, 1 };

// the subnet mask
byte subnet[] = { 255, 255, 255, 0 };

// Initialize the Ethernet server library
EthernetServer server(80);

// derive an instance of the HTTPserver class with custom handlers
class myServerClass : public HTTPserver
  {
  virtual void processPostType        (const char * key, const byte flags);
  virtual void processPathname        (const char * key, const byte flags);
  virtual void processHttpVersion     (const char * key, const byte flags);
  virtual void processGetArgument     (const char * key, const char * value, const byte flags);
  virtual void processHeaderArgument  (const char * key, const char * value, const byte flags);
  virtual void processCookie          (const char * key, const char * value, const byte flags);
  virtual void processPostArgument    (const char * key, const char * value, const byte flags);

  };  // end of myServerClass

myServerClass myServer;

// -----------------------------------------------
//  User handlers
// -----------------------------------------------

void myServerClass::processPostType (const char * key, const byte flags)
  {
          println(F("HTTP/1.1 200 OK")); //send new page
          println(F("Content-Type: text/html"));
          println();

          println(F("<HTML>"));
          println(F("<HEAD>"));
          println(F("</HEAD>"));
          println(F("<BODY>"));
          println(F("<body bgcolor='Turquoise'>"));
          println(F("<h1><b><center>GAS TURBINE E CONTROL PANEL</b></h2><font size=5>"));
          println(F("<hr/><p> Click the Buttons to turn On and OFF <p/><hr/><br/><br/><br/>"));
          print(F("<input type=button value=OPERATION style=position:absolute;left:976px;top:110px;width:150px;height:30px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?off3579'>&nbsp;&nbsp;"));
          print(F("<input type=button value=OFF style=position:relative;left:840px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?OFF'>"));
          print(F("<input type=button value='CRANK' style=position:relative;left:850px;top:85px;width:85px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?CRK'>"));
          print(F("<input type=button value=FIRE style=position:relative;left:860px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?FIR'>"));
          print(F("<input type=button value=AUTO style=position:relative;left:870px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?AUT'>"));
          print(F("<input type=button value=REM style=position:relative;left:880px;top:85px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?REM'>"));
          print(F("<input type=button value=LOAD style=position:absolute;left:975px;top:230px;width:150px;height:30px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?off3579'>&nbsp;&nbsp;"));
          print(F("<input type=button value=PRESEL style=position:relative;left:540px;top:205px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?PRS'>"));
          print(F("<input type=button value=BASE style=position:relative;left:560px;top:205px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?BAS'>"));
          print(F("<input type=button value=PEAK style=position:relative;left:580px;top:205px;width:70px;height:50px;color:blue;font-size:16px;border-width:5px;border-style:ridge;border-color:blue; onmousedown=location.href='/?PEK'><br>"));

  } // end of processPostType

void myServerClass::processPathname (const char * key, const byte flags)
  {
  /*
  print (F("<p>Pathname: "));
  fixHTML (key);
  println ();
  */
  }  // end of processPathname

void myServerClass::processHttpVersion (const char * key, const byte flags)
  {
  /*
  print (F("<p>HTTP version: "));
  println (key);
  */
  }  // end of processHttpVersion

void myServerClass::processGetArgument (const char * key, const char * value, const byte flags)
  {
  print (F("<p>Get argument: "));
  fixHTML (key);
  print (F(" = "));
  fixHTML (value);
  println ();
  }  // end of processGetArgument

void myServerClass::processHeaderArgument (const char * key, const char * value, const byte flags)
  {
  /*
  print (F("<pre>Header argument: "));
  fixHTML (key);
  print (F(" = "));
  fixHTML (value);
  println ("</pre>");
  */
  }  // end of processHeaderArgument

void myServerClass::processCookie (const char * key, const char * value, const byte flags)
  {
  /*
  print (F("<p>Cookie: "));
  fixHTML (key);
  print (F(" = "));
  fixHTML (value);
  println ();
  */
  }  // end of processCookie

void myServerClass::processPostArgument (const char * key, const char * value, const byte flags)
  {
  /*
  print (F("<p>Post argument: "));
  fixHTML (key);
  print (F(" = "));
  fixHTML (value);
  println ();
  */
  }  // end of processPostArgument
 

// -----------------------------------------------
//  End of user handlers
// -----------------------------------------------

void setup ()
  {
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip, gateway, subnet);
  }  // end of setup

void loop ()
  {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (!client)
    {
    // do other processing here
    return;
    }

  myServer.begin (&client);
  while (client.connected() && !myServer.done)
    {
    while (client.available () > 0 && !myServer.done)
      myServer.processIncomingByte (client.read ());

    // do other stuff here

    }  // end of while client connected

  myServer.println(F("<br />"));
  myServer.println(F("<br />"));
  myServer.println(F("</BODY>"));
  myServer.println(F("</HTML>"));
  myServer.flush ();
 
  // give the web browser time to receive the data
  delay(10);
  // close the connection:
  client.stop();

  }  // end of loop


You'll have to add back the stuff to control the pins, but that should be easy enough.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jurs

Please help me. I have attached my full sketch my sketch
Which Arduino board are you using?

The sketch is rather big.

After fixing some problems with your code and after improving the speed so that load time is only the fraction of a second, I found:
Code: [Select]

Sketch uses 32,926 bytes (102%) of program storage space. Maximum is 32,256 bytes.
...
Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.


What's more important for you:
Use an UNO board and try somehow to fit it on an UNO?
Or use a MEGA or other board with more than 32KB of flash memory?

nickgammon

#9
Aug 15, 2015, 12:16 am Last Edit: Aug 15, 2015, 12:17 am by Nick Gammon
Code: [Select]

          print(F("<input type=button value=F0 style=position:absolute;left:775px;top:150px;width:60px;height:50px;color:DarkRed;font-weight:bold;font-size:16px;border-width:5px;border-style:ridge;border-color:DarkRed; onmousedown=location.href='/?F0'>&nbsp;&nbsp;"));
          print(F("<input type=button value=F1 style=position:absolute;left:775px;top:230px;width:60px;height:50px;color:DarkRed;font-weight:bold;font-size:16px;border-width:5px;border-style:ridge;border-color:DarkRed; onmousedown=location.href='/?F1'>&nbsp;&nbsp;"));
          print(F("<input type=button value=F2 style=position:absolute;left:775px;top:310px;width:60px;height:50px;color:DarkRed;font-weight:bold;font-size:16px;border-width:5px;border-style:ridge;border-color:DarkRed; onmousedown=location.href='/?F2'>&nbsp;&nbsp;"));
          print(F("<input type=button value=F3 style=position:absolute;left:775px;top:390px;width:60px;height:50px;color:DarkRed;font-weight:bold;font-size:16px;border-width:5px;border-style:ridge;border-color:DarkRed; onmousedown=location.href='/?F3'>&nbsp;&nbsp;"));
          print(F("<input type=button value=F4 style=position:absolute;left:775px;top:470px;width:60px;height:50px;color:DarkRed;font-weight:bold;font-size:16px;border-width:5px;border-style:ridge;border-color:DarkRed; onmousedown=location.href='/?F4'>&nbsp;&nbsp;"));
          print(F("<input type=button value=F5 style=position:absolute;left:775px;top:550px;width:60px;height:50px;color:DarkRed;font-weight:bold;font-size;border-width:5px;border-style:ridge;border-color:DarkRed; onmousedown=location.href='/?F5'>&nbsp;&nbsp;"));



Have you considered writing a function to output this? Try to remember that you have limited RAM and program memory. You have the words "color:DarkRed;font-weight:bold;font-size:16px;border-width:5px;border-style:ridge;border-color:DarkRed; onmousedown=location.href" repeated many times. Write a function that takes the variable parts, and outputs the line for you. Also the code would be much easier to read.




Quote
Use an UNO board and try somehow to fit it on an UNO?
There's no "somehow" about it. The code is incredibly inefficiently written.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

YemSalat

As long as you are using the default Ethernet library - you will never be able to make it fast.

Ethernet library that comes with Arduino is flawed and has errors in it, that make it so that the server 'hangs' for 5-7 seconds. (AFAIK something to do with not picking the right socket)

YemSalat

#11
Aug 15, 2015, 01:29 am Last Edit: Aug 15, 2015, 01:41 am by YemSalat
Have you considered writing a function to output this?
To save more space - you can also use a CSS class, so you son't have to repeat your styles all the time.
And put all this in there:
Code: [Select]

input[type="button"] {
  position:absolute;
  width:60px;
  height:50px;
  color:DarkRed;
  font-weight:bold;
  font-size:16px;
  border-width:5px;
  border-style:ridge;
  border-color:DarkRed;  /* you dont really need this, if left unset 'border-color' will be same as 'color' */
}

nickgammon

The advantage of that would be to actually lower the time taken to send, where making a function still sends the same stuff. So YemSalat's suggestion is the better one.

However you could still make a function to draw the buttons, using the CSS class.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

SurferTim

As long as you are using the default Ethernet library - you will never be able to make it fast.
You will not make it fast like a Apache server running on a PC, but I can make it pretty darned fast. Read reply #9. Nick Gammon cut the download time to 1/5 the original time.

Ethernet library that comes with Arduino is flawed and has errors in it, that make it so that the server 'hangs' for 5-7 seconds. (AFAIK something to do with not picking the right socket)
Can you show me your code that does that? I have never had any of my servers hang for 5 to 7 seconds. Mine picks an available socket every time, unless there is not one available.

I've made my server code about as bulletproof as I can. I intentionally torture it with things that would crash about any other server example around. Give it a try. See if you can crash it.
http://playground.arduino.cc/Code/WebServerST
If you enter an 'r' on the serial monitor and press the enter key, it will display the status for all sockets.

YemSalat

#14
Aug 15, 2015, 02:49 am Last Edit: Aug 15, 2015, 04:09 am by YemSalat
You will not make it fast like a Apache server running on a PC
I'll grant you that.

Can you show me your code that does that? I have never had any of my servers hang for 5 to 7 seconds. Mine picks an available socket every time, unless there is not one available.
Perhaps I should just quote the library code from EthernetClient.cpp:
Code: [Select]

EthernetClient EthernetServer::available() {
  accept();

  for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
    EthernetClient client(sock);
    if (EthernetClass::_server_port[sock] == _port &&
        (client.status() == SnSR::ESTABLISHED ||
         client.status() == SnSR::CLOSE_WAIT)) {
      if (client.available()) {
        // XXX: don't always pick the lowest numbered socket.
        return client;
      }
    }
  }
  return EthernetClient(MAX_SOCK_NUM);
}

Notice this?
// XXX: don't always pick the lowest numbered socket


Here is how this can be fixed:
Code: [Select]

EthernetClient EthernetServer::available_(int sock) {
  accept_(sock);
  EthernetClient client(sock);
  if (EthernetClass::_server_port[sock] == _port &&
      (client.status() == SnSR::ESTABLISHED ||
       client.status() == SnSR::CLOSE_WAIT)) {
    if (client.available()) {
      return client;
    }
  }
  return EthernetClient(MAX_SOCK_NUM);
}


And also need to redefine the accept function:
Code: [Select]

void EthernetServer::accept_(int sock) {
  int listening = 0;
  EthernetClient client(sock);

  if (EthernetClass::_server_port[sock] == _port) {
    if (client.status() == SnSR::LISTEN) {
      listening = 1;
    }
    else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) {
      client.stop();
    }
  }

  if (!listening) {
    //begin();
    begin_(sock); // added
  }
}


Also, update EthernetServer.h to use the 'redefined' functions:
Code: [Select]

class EthernetServer :
public Server {
private:
  uint16_t _port;
  //void accept();
  void accept_(int sock);
public:
  EthernetServer(uint16_t);
  //EthernetClient available();
  EthernetClient available_(int sock);
  virtual void begin();
  virtual void begin_(int sock);
  virtual size_t write(uint8_t);
  virtual size_t write(const uint8_t *buf, size_t size);
  using Print::write;
};



NOTE: this solution is not mine, the original solution was posted by @smart_alex about a week ago, but I don't think it is available in English, so just reposting here in case others find it useful.

In his test he got the following results (I was also experimenting with Ethernet for the past couple days and notice delays as well)

PS:
мс = ms = milliseconds
с = s = seconds



Before modifications to the library:


After


As you may see it is still not perfect (3s delay on style.css) but still much better then original.

Complete modified EthernetServer.cpp:
Code: [Select]

/*
Mod for Arduino Mega Server project
fix bug delay answer server
*/

#include "w5100.h"
#include "socket.h"
extern "C" {
#include "string.h"
}

#include "Ethernet.h"
#include "EthernetClient.h"
#include "EthernetServer.h"

EthernetServer::EthernetServer(uint16_t port) {
_port = port;
}

void EthernetServer::begin() {
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);
if (client.status() == SnSR::CLOSED) {
socket(sock, SnMR::TCP, _port, 0);
listen(sock);
EthernetClass::_server_port[sock] = _port;
break;
}
}
}

void EthernetServer::begin_(int sock) {
EthernetClient client(sock);
if (client.status() == SnSR::CLOSED) {
socket(sock, SnMR::TCP, _port, 0);
listen(sock);
EthernetClass::_server_port[sock] = _port;
}
}

/*

void EthernetServer::accept() {
int listening = 0;

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);

if (EthernetClass::_server_port[sock] == _port) {
if (client.status() == SnSR::LISTEN) {
listening = 1;
}
else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) {
client.stop();
}
}
}

if (!listening) {
begin();
}
}

*/

void EthernetServer::accept_(int sock) {
int listening = 0;
EthernetClient client(sock);

if (EthernetClass::_server_port[sock] == _port) {
if (client.status() == SnSR::LISTEN) {
listening = 1;
}
else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) {
client.stop();
}
}

if (!listening) {
//begin();
begin_(sock); // added
}
}

/*

EthernetClient EthernetServer::available() {
accept();

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);
if (EthernetClass::_server_port[sock] == _port &&
(client.status() == SnSR::ESTABLISHED ||
client.status() == SnSR::CLOSE_WAIT)) {
if (client.available()) {
// XXX: don't always pick the lowest numbered socket.
return client;
}
}
}
return EthernetClient(MAX_SOCK_NUM);
}

*/

EthernetClient EthernetServer::available_(int sock) {
accept_(sock);
EthernetClient client(sock);
if (EthernetClass::_server_port[sock] == _port &&
(client.status() == SnSR::ESTABLISHED ||
client.status() == SnSR::CLOSE_WAIT)) {
if (client.available()) {
return client;
}
}
return EthernetClient(MAX_SOCK_NUM);
}

size_t EthernetServer::write(uint8_t b) {
return write(&b, 1);
}

size_t EthernetServer::write(const uint8_t *buffer, size_t size) {
size_t n = 0;
//accept();

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
accept_(sock); // added
EthernetClient client(sock);

if (EthernetClass::_server_port[sock] == _port &&
client.status() == SnSR::ESTABLISHED) {
n += client.write(buffer, size);
}
}
return n;
}


EthernetServer.h
Code: [Select]

/*
Mod for Arduino Mega Server project
fix bug delay answer server
*/

#ifndef ethernetserver_h
#define ethernetserver_h

#include «Server.h»

class EthernetClient;

class EthernetServer:
public Server {
private:
uint16_t _port;
//void accept();
void accept_(int sock);
public:
EthernetServer(uint16_t);
//EthernetClient available();
EthernetClient available_(int sock);
virtual void begin();
virtual void begin_(int sock);
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buf, size_t size);
using Print::write;
};

#endif


[Edit] made images 'clickable'
[Edit 2] added complete modified versions of EthernetServer, all credit to @smart_alex

Go Up