Arduino Uno + Ethernet code help

So I have found the code for a Arduino web server here on the forums that allows images and CSS files to be supplied to the client on request but I do not understand some parts of the code. I have been looking through this whole forum for tips how to program this myself but most of the popular codes didn't work for me.

This is the code that I found and is working flawlessly.

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

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xE7, 0xAC };
IPAddress ip(192, 168, 1, 20); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

File webFile;
char header[80];
char filename[80];
int txtlen;
uint8_t buf[64];
int aantal;

void setup()
{
    pinMode(53, OUTPUT);
    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.");
}

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

    txtlen = 0;
    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
                if (txtlen < 79) {
                  header[txtlen++] = c;
                  header[txtlen] = 0;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                Serial.write(c);
                if (c == '\n' && currentLineIsBlank) {
                  ExtractFileName();
                  Serial.print("Extracted filename is: ");
                  Serial.println(filename);
                  webFile = SD.open(filename);            // open web file
                  if (!webFile) {
                    Serial.println("File not found!!");
                    client.println("HTTP/1.1 404 NOT FOUND");
                  }
                  else {
                    // 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
                  if (webFile) {
                        while(aantal = webFile.available()) {
                            if (aantal > 64) {					
                              webFile.read(buf, 64);
                              client.write(buf, 64);
                            }
                            else {
                              webFile.read(buf, aantal);                              
                              client.write(buf, aantal); // 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(100);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

void ExtractFileName()
{
  int i, j;
  
  i=0;
  while (header[i++] != ' ') {
    ;
  }
  j=0;
  while (header[i] != ' ') {
    filename[j++] = header[i++];
  }
  filename[j] = 0;
  if (filename[0] == '/' && filename[1] == 0) {
    strcpy(filename, "index.htm");
  }
}

The author of the code posted it as a reply in a topic with a similar issue I had but he didn't post this code anywhere else and it isn't commented enough for me to understand why he programed some things the way he did. The main confusing parts are the "int aantal;" variable. I am not sure what the point of that variable is, and I don't understand how his function ExtractFileName works. I understand the rest of the code more or less, its just that I don't understand the logic behind some of the code as I am working with HTTP requests for the first time.

  while(aantal = webFile.available()) {
                            if (aantal > 64) {					
                              webFile.read(buf, 64);
                              client.write(buf, 64);
                            }
                            else {
                              webFile.read(buf, aantal);                              
                              client.write(buf, aantal); // send web page to client
                            }

It looks to me like he is reading data in chunks of no more than 64 bytes.

That looks like zoomkat's code, or someone copying his code. The purpose of the 64 byte sends is to increase the speed of the send. If you send the response in 64 byte packets rather than 1 byte packets, you get a 4x speed increase.

Thanks for answering guys.

So the aantal variable i just there to check if the file is bigger than 64 bytes? And if it is it sends it in 64 byte chunks, else it just sends it as big as it is (63 bytes or less)?

Did you guys understand the ExtractFileName function?

void ExtractFileName()
{
  int i, j;
  
  i=0;
  while (header[i++] != ' ') {
    ;
  }
  j=0;
  while (header[i] != ' ') {
    filename[j++] = header[i++];
  }
  filename[j] = 0;
  if (filename[0] == '/' && filename[1] == 0) {
    strcpy(filename, "index.htm");
  }
}

I don't understand why he is using 2 counters here and what his output is supposed to be. Is this just a way of copy pasting a word letter by letter or what?

I'm surprised zoomkat hasn't jumped in here yet, but I would do a forum search for zoomkat's server code with the SD file stuff. He does that correct and it is fast.

Skip spaces:

  i=0;
  while (header[i++] != ' ') {
    ;
  }

Find the next space (copying back to the start of the buffer):

  j=0;
  while (header[i] != ' ') {
    filename[j++] = header[i++];
  }

Null-terminate at that space:

  filename[j] = 0;

Thanks for the explanation,

I was trying to find some of zoomkat's webserver sketches but the search is very hard to use to get useful things back. I seen 1 sketch but it had servo variables that I don't need, maybe I cut out too much code from it because it didn't work for me, I tried going through his profile but he got over 7k posts so its hard to find the exact posts where he posted the webserver with SD card support.

Ill try some of his code that I did find around other people's posts and see how it turns out because I need a code that I can easily understand and this code I found is a bit too complicated for me. Id rather have a simple code that I can learn how to tweak, than a complicated one that I am afraid to touch not to break things.

Thank you very much guys, and if you have any useful SD card webserver links (zoomkats maybe) be sure to link them as I have been failing in finding them.

Below are some of the previous discussions and the basic test code for up loading files from the SD card in large packets.

http://forum.arduino.cc/index.php?topic=134868.msg1014221#msg1014221

http://forum.arduino.cc/index.php/topic,144675.0.html

http://forum.arduino.cc/index.php/topic,152598.0.html

//zoomkat 12/26/12
//SD server test code
//open serial monitor to see what the arduino receives
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields

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

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
String readString; 

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

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");
}

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 

            client.println("HTTP/1.1 200 OK"); //send new page
          //client.println("Content-Type: text/html");
          client.println("Content-Type: image/jpeg");
          //client.println("Content-Type: image/gif");
          //client.println("Content-Type: application/x-javascript");
          //client.println("Content-Type: text");

          client.println();

          //File myFile = SD.open("boom.htm");
          File myFile = SD.open("HYPNO.JPG");
          //File myFile = SD.open("BLUEH_SL.GIF");
          //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)
              {
                // Serial.println("Packet");
                client.write(clientBuf,64);
                clientCount = 0;
              }
            }
            //final <64 byte cleanup packet
            if(clientCount > 0) client.write(clientBuf,clientCount);            
            // close the file:
            myFile.close();
          }
          delay(1);
          //stopping client
          client.stop();
          readString="";
        }
      }
    }
  } 
}

Thank you for the codes zoomkat.

I got another question related to my Arduino Web Server.

Is it possible to connect to the Arudino via DNS? Like set it up so that my Arduino has a address like "www.example.com" or some other way. I only managed to find ways for the Arduino to connect to websites via DNS but no examples for a client connecting to the Arduino using a URL instead of the IP address its given.

Sure. Buy a domain name and have the registrar do the dns resolution for you to the public ip of the Arduino.

I only managed to find ways for the Arduino to connect to websites via DNS but no examples for a client connecting to the Arduino using a URL instead of the IP address its given.

The Arduino is a web server, not a domain server. In order to address it by name, you need to get all the DNS servers in the world to know the name and IP address. That is typically done by buying a domain, and registering the IP address that hosts that domain.

Unless the Arduino has a static IP address, not just a local IP address, you won't be able to register its IP address.