Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 6 of 6

Thread: Network Server – I need more speed scotty

  1. #1

    Network Server – I need more speed scotty

    Having got my project up and running, the only remaining issue is speed. A simple test page with a 50KB image takes about 3.5 seconds to load, when hosted on the SD card on a Teensy 3.1 using the Wiz820 SD adapter. The code is based on part 11 of this tutorial. I did try another SD library, which didn’t make any difference so I am guessing it’s the code or network. I think all of the web server samples I have found use the same method of reading 1 byte at a time, which I guess is the bottleneck. Has anyone done anything similar and improved the code for better speed? (I did some searches on these forums and did see Paul mention about improving the Ethernet library, did this ever happen?)

    Here's the code...

    Code:
    /*--------------------------------------------------------------
      Program:      eth_websrv_SD_image
    
      Description:  Arduino web server that serves up a basic web
                    page that displays an image.
      
      Hardware:     Arduino Uno and official Arduino Ethernet
                    shield. Should work with other Arduinos and
                    compatible Ethernet shields.
                    2Gb micro SD card formatted FAT16
                    
      Software:     Developed using Arduino 1.0.5 software
                    Should be compatible with Arduino 1.0 +
                    
                    Requires index.htm, page2.htm and pic.jpg to be
                    on the micro SD card in the Ethernet shield
                    micro SD card socket.
      
      References:   - WebServer example by David A. Mellis and 
                      modified by Tom Igoe
                    - SD card examples by David A. Mellis and
                      Tom Igoe
                    - Ethernet library documentation:
                      http://arduino.cc/en/Reference/Ethernet
                    - SD Card library documentation:
                      http://arduino.cc/en/Reference/SD
    
      Date:         7 March 2013
      Modified:     17 June 2013
     
      Author:       W.A. Smith, http://startingelectronics.com
    --------------------------------------------------------------*/
    
    #include <SPI.h>
    #include <Ethernet.h>
    #include <SD.h>
    
    // size of buffer used to capture HTTP requests
    #define REQ_BUF_SZ   20
    
    // MAC address from Ethernet shield sticker under board
    byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
    IPAddress ip(192, 168, 0, 20); // IP address, may need to change depending on network
    EthernetServer server(80);  // create a server at port 80
    File webFile;
    char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
    char req_index = 0;              // index into HTTP_req buffer
    
    void setup()
    {
        // disable Ethernet chip
        pinMode(10, OUTPUT);
        digitalWrite(10, HIGH);
        
        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("test.htm")) {
            Serial.println("ERROR - Can't find test.htm file!");
            return;  // can't find index file
        }
        Serial.println("SUCCESS - Found index.htm file.");
        
        Ethernet.begin(mac, ip);  // initialize Ethernet device
        server.begin();           // start to listen for clients
    }
    
    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
                    // buffer first part of HTTP request in HTTP_req array (string)
                    // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                    if (req_index < (REQ_BUF_SZ - 1)) {
                        HTTP_req[req_index] = c;          // save HTTP request character
                        req_index++;
                    }
                    // print HTTP request character to serial monitor
                    Serial.print(c);
                    // last line of client request is blank and ends with \n
                    // respond to client only after last line received
                    if (c == '\n' && currentLineIsBlank) {
                        // open requested web page file
                        if (StrContains(HTTP_req, "GET / ")
                                     || StrContains(HTTP_req, "GET /index.htm")) {
                            client.println("HTTP/1.1 200 OK");
                            client.println("Content-Type: text/html");
                            client.println("Connnection: close");
                            client.println();
                            webFile = SD.open("test.htm");        // open web page file
                        }
                         else if (StrContains(HTTP_req, "GET /pic.jpg")) {
                            webFile = SD.open("pic.jpg");
                            if (webFile) {
                                client.println("HTTP/1.1 200 OK");
                                client.println();
                            }
                        }
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // send web page to client
                            }
                            webFile.close();
                        }
                        // reset buffer index and all buffer elements to 0
                        req_index = 0;
                        StrClear(HTTP_req, REQ_BUF_SZ);
                        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)
    }
    
    // sets every element of str to 0 (clears array)
    void StrClear(char *str, char length)
    {
        for (int i = 0; i < length; i++) {
            str[i] = 0;
        }
    }
    
    // searches for the string sfind in the string str
    // returns 1 if string found
    // returns 0 if string not found
    char StrContains(char *str, char *sfind)
    {
        char found = 0;
        char index = 0;
        char len;
    
        len = strlen(str);
        
        if (strlen(sfind) > len) {
            return 0;
        }
        while (index < len) {
            if (str[index] == sfind[found]) {
                found++;
                if (strlen(sfind) == found) {
                    return 1;
                }
            }
            else {
                found = 0;
            }
            index++;
        }
    
        return 0;
    }
    I have attached the test htm, image and sketch in a zip file for anyone wanting to test this.

    Thanks in advance.

    Les
    Attached Files Attached Files

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,122
    Perhaps try changing this code?

    Code:
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // send web page to client
                            }
                            webFile.close();
                        }
    This processes the entire file 1 byte at a time. Perhaps it would be faster if you used a buffer?

    Maybe something like this?

    Code:
                        if (webFile) {
                            byte buf[512];
                            while (1) {
                                int n = webFile.available();
                                if (n == 0) break;
                                if (n > 512) n = 512;
                                webFile.read(buf, n);
                                client.write(buf, n);
                            }
                            webFile.close();
                        }
    This is untested. I just made it up for this message. Please let me know if it works, and what kind of speed difference it makes?

  3. #3
    Thanks for the quick reply Paul.

    That has made a massive difference.

    On my Asus Prime tablet with the original code the page took 12 seconds to load. With your code it's 0.2 seconds. It's almost like it's cached now.

    Regards,

    Les

  4. #4
    OK hopefully the last question on this.

    I have multiple images on my web page, (about 20) any suggestions on the best way to deal with them? I don't think I want to write an if statement for each one, unless it will be the fastest way.

    Regards,

    Les

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,122
    I'm glad that tiny chunk of code made a 60X speedup

    A big if-else statement might be the fastest way. But speeding up that part probably makes little difference. It'd be slower to read the SD card to search for file names. Storing an array of names and looping through it for a search would probably be nearly as fast as the if-else code, but might make for smaller & simpler code.

  6. #6
    Quote Originally Posted by PaulStoffregen View Post
    I'm glad that tiny chunk of code made a 60X speedup

    A big if-else statement might be the fastest way. But speeding up that part probably makes little difference. It'd be slower to read the SD card to search for file names. Storing an array of names and looping through it for a search would probably be nearly as fast as the if-else code, but might make for smaller & simpler code.
    It's amazing the difference a few lines of code makes.

    I was using an array for the images, but I have simplified things and sped it up even more by using a single image for the icons and using CSS sprites. I now only have 2 image requests instead of 15.

    Thanks again for your help.

    Les

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •