Go Down

Topic: Arduino + Ethernet - webserver is SLOW (Read 1 time) previous topic - next topic

Danny182

hello,
I have an Arduino atmega2560 and the ethernet shield.
I uploaded a simple index file on the SDcard. it doens't load the images that are 4KB but they wont load. and I'm working in my LAN.
so if I digit 192.168.2.10:81 it loads just the text of the index.htm

can someone help me out? this is the code
Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 2, 10); // IP address, may need to change depending on network
EthernetServer server(81);  // create a server at port 80

File webFile;

void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for debugging
   
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    // send web page
                    webFile = SD.open("index.htm");        // open web page file
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                }
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

billroy

That code only knows how to serve one file: index.html.

When you serve index.html, and it references an image, the browser asks your code for the image file.  What does it get in return?

Your code must serve the contents of the image file, too, when it's requested.  You'll find you need to change the Content-Type header for images to work properly.

There is code on the forum to do what you want, if you search a bit.  I'd start with "web server sd card images".

-br

Danny182


That code only knows how to serve one file: index.html.

When you serve index.html, and it references an image, the browser asks your code for the image file.  What does it get in return?

Your code must serve the contents of the image file, too, when it's requested.  You'll find you need to change the Content-Type header for images to work properly.

There is code on the forum to do what you want, if you search a bit.  I'd start with "web server sd card images".

-br



thank you for the reply.
I thought that once I open the index file then it links the images with that file.
it doesn't load the image that should be the background (body), can you please explain how should i change my code?
thank you

zimm0who0net

FYI:  This section is crazy inefficient

Code: [Select]
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }


The reason is because each call to client.write() will send a full IP packet with only the one character in it.  That's insane overhead.  To make things a-m-a-z-i-n-g-l-y faster, read blocks of data from the file and then write the blocks to the buffer.

Incidentally, make your block size 512 bytes.  Why?  Well, when you read data with the SD library it'll read into it's own internal cache buffer and then copy that data to your passed in buffer.  That's an extra memcpy step that you don't really need.  If you make your buffer exactly 512 bytes, it'll bypass the internal cache, and write data directly from the card to your buffer.

512 isn't the most efficient for the TCP side of things because you have a max of about 1400 bytes in a packet, but it's not that much slower.  If you want something really efficient, create two contiguous 512 byte buffers and then send them both.  But that's a lot more overhead, so I wouldn't bother.

Incidentally, The W5100 has a 2k write buffer just sitting there not being used.  Seems stupid that you have to allocate a 512 byte buffer in RAM to get around this issue when the library could handle all this for you without using any RAM.  That's exactly what happens with the UDP library.  Unfortunatly, the powers that be have decided that this is not a high priority...

Danny182


FYI:  This section is crazy inefficient

Code: [Select]
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }


The reason is because each call to client.write() will send a full IP packet with only the one character in it.  That's insane overhead.  To make things a-m-a-z-i-n-g-l-y faster, read blocks of data from the file and then write the blocks to the buffer.

Incidentally, make your block size 512 bytes.  Why?  Well, when you read data with the SD library it'll read into it's own internal cache buffer and then copy that data to your passed in buffer.  That's an extra memcpy step that you don't really need.  If you make your buffer exactly 512 bytes, it'll bypass the internal cache, and write data directly from the card to your buffer.

512 isn't the most efficient for the TCP side of things because you have a max of about 1400 bytes in a packet, but it's not that much slower.  If you want something really efficient, create two contiguous 512 byte buffers and then send them both.  But that's a lot more overhead, so I wouldn't bother.

Incidentally, The W5100 has a 2k write buffer just sitting there not being used.  Seems stupid that you have to allocate a 512 byte buffer in RAM to get around this issue when the library could handle all this for you without using any RAM.  That's exactly what happens with the UDP library.  Unfortunatly, the powers that be have decided that this is not a high priority...


I think that there is a way to let it go, because it's impossibile that it cannot load a png image of 4kb.
if it can't load that I can't understand why they call it WebServer.

zimm0who0net

It's a sample.  It doesn't parse the request from the browser at all.  It only sends the one file.  It's a stretch to call it a web server I agree, but it's a sample. 

billroy

Show us the contents of the index.html file you are trying to render, please?

The web server code you posted, if you read it, only knows how to serve one file.

-br

zoomkat

Some server code that uploads files from the SD card fairly quickly.

Code: [Select]

//zoomkat 2/26/13
//SD server slider test code
//open serial monitor to see what the arduino receives
//browser address will look like http://192.168.1.102:84/servosld.htm when submited
//for use with W5100 based ethernet shields
//put the servosld.htm, slider.js, bluev_sl.gif,
//and bluev_bg.gif on the SD card
//download flies at:
// http://web.comporium.net/~shb/pix/servosld.htm
// http://web.comporium.net/~shb/pix/slider.js
// http://web.comporium.net/~shb/pix/bluev_bg.gif
// http://web.comporium.net/~shb/pix/bluev_sl.gif
//

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

#include <Servo.h>
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo
Servo myservoe, myservof, myservog; // myservoh not used due to lack of another free pin
String readString, pos;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // 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

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

void setup(){

  Serial.begin(9600);

  // disable w5100 while setting up SD
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);
  Serial.print("Starting SD..");
  if(!SD.begin(4)) Serial.println("failed");
  else Serial.println("ok");

  Ethernet.begin(mac, ip, gateway, gateway, subnet);

  //delay(2000);
  server.begin();
  Serial.println("Ready");

  myservoa.attach(2);  //the pin for the servoa control
  myservob.attach(3);  //the pin for the servob control
  myservoc.attach(5);  //the pin for the servoc control
  myservod.attach(6);  //the pin for the servod control
  myservoe.attach(7);  //the pin for the servoa control
  myservof.attach(8);  //the pin for the servob control
  myservog.attach(9);  //the pin for the servoc control
  //myservoh.attach(10);  //the pin for the servod control

}

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

            //select proper header for file to be sent to browser

          client.println("HTTP/1.1 200 OK"); //send new page
          if(readString.indexOf("servosld") >=0) {
            client.println("Content-Type: text/html");
            client.println();
          }

          if(readString.indexOf("slider") >=0) {
            client.println("Content-Type: application/x-javascript");
            client.println();
          }

          if(readString.indexOf("bluev") >=0) {
            client.println("Content-Type: image/gif");
            client.println();
          }

          //select file to send to browser
          if(readString.indexOf("servosld") >=0) {
            File myFile = SD.open("SERVOSLD.HTM");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);           
              myFile.close();
            }
          }

          if(readString.indexOf("slider") >=0) {
            File myFile = SD.open("slider.js");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_sl") >=0) {
            File myFile = SD.open("bluev_sl.gif");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_bg") >=0) {
            File myFile = SD.open("bluev_bg.gif");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);
              myFile.close();
            }
          }

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

          //process GET string request from client and and position servo

          pos = readString.substring(8, 12); //get the first four characters         
          //Serial.println(pos);
          int n = pos.toInt();  //convert readString into a number   
          Serial.println(n);
          Serial.println();

          if(readString.indexOf("?0") >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf("?1") >0) myservob.writeMicroseconds(n);
          if(readString.indexOf("?2") >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf("?3") >0) myservod.writeMicroseconds(n);
          if(readString.indexOf("?4") >0) myservoe.writeMicroseconds(n);
          if(readString.indexOf("?5") >0) myservof.writeMicroseconds(n);
          if(readString.indexOf("?6") >0) myservog.writeMicroseconds(n);
          //only seven servo pins, so back to myservoa for testing
          if(readString.indexOf("?7") >0) myservoa.writeMicroseconds(n);

          //clearing string for next read
          readString="";
          pos="";
        }
      }
    }
  }
}


Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

Danny182


Show us the contents of the index.html file you are trying to render, please?

The web server code you posted, if you read it, only knows how to serve one file.

-br



Code: [Select]
<html>
   <head>
<title>1</title>
   
   </head>

<body background="bgp.png">
1
</body>
</html>


this is in the root of the sd:
http://imageshack.us/a/img46/2042/catturapm.jpg

Go Up