Ethernet client - how to make HTTP request as fast as possible

Hi,

I am trying to achieve as fast as possible HTTP request from my arduino so I am thinking about minimizing the code for ethernet client part. The question is - can I skip client.read() part in my code? Or does it have to be there? I removed it and it seems to behave strange - I see the request on the server but they are delayed (1 loop late). I am calling the function like this example:

sendData("GET /test.php HTTP/1.0");

bool sendData(char *page)
{
        bool cconn=false;
        unsigned int connectLoop=0;
        do //try connecting until connected or timeout
        {
                connectLoop++;
                cconn = client.connect(IPAddress(192,168,2,106),80);
                if ( connectLoop > 10000 ) return 1; //timeout if too many not succsssfull attempts
        }
        while ( cconn == false );

        if ( cconn == 1 )
        {
                client.println(page);
                client.println(F("Host: 192.168.2.106"));
                client.println(F("\r\n"));
                connectLoop = 0;
                while (!client.available())
                {
                        connectLoop++;
                        if ( connectLoop > 10000 ) return 1; //timeout if client was not available for long time
                }
                connectLoop = 0;
                while (client.read() > 0)
                {
                        connectLoop++;
                        if ( connectLoop > 10000 ) return 1; //timeout if reading data took too long
                }
                client.stop();
                return 0;
        }
}

fanofard:                client.println(page);                client.println(F("Host: 192.168.2.106"));                client.println(F("\r\n"));

Typically when programming microcontrollers we are very anxious to avoid any unnecessary use of SRAM and for that reason it's usually a good idea to use the F() macro to put strings in flash. However, the way Print works is it sends a separate packet for each character of those __FlashStringHelper strings. Also, println sends the newline as a separate packet. Every packet has a certain amount of overhead so if you want to go fast you need to send the fewest number as possible to get the job done. So if you want to optimize for speed rather than SRAM try changing those lines to this:

                client.print(page);
                client.print("\r\nHost: 192.168.2.106\r\n\r\n\r\n");

If any of those newlines in hostString are unnecessary then get rid of them, I'm just reproducing what your code did originally. That just took you from sending 24 packets to only sending two packets!

If you want to get it down to 1 packet you can assemble the entire string in memory and send it all at once:

                const char hostString[] = "\r\nHost: 192.168.2.106\r\n\r\n\r\n";
                char response[strlen(page) + strlen(hostString) + 1];
                strcpy(response, page);
                strcat(response, hostString);
                client.print(response);

Thanks for the hint! I will try it.

And how about the client.read() part? Does anybody know if it is really necessary to read the data or can it somehow be omitted?

EDIT: I tried the above recommendation and it works. I am not able to tell if it is faster or not as I do not know how to measure it. I tried measuring by millis() at the beginning and the end of the function. It reported ~650ms but it was roughly the same value even if I use 3x client.println(). But I am not sure how this millis measurement and serial printing affects overal speed. This is my current code with millis measurement:

bool sendData(char *page)
{
        eth_time = millis();
        bool cconn=false;
        unsigned int connectLoop=0;
        do //try connecting until connected or timeout
        {
                connectLoop++;
                cconn = client.connect(IPAddress(192,168,2,106),80);
                if ( connectLoop > 10000 ) return 1; //timeout if too many not succsssfull attempts
        }
        while ( cconn == false );

        if ( cconn == 1 )
        {
                const char hostString[] = "\r\nHost: 192.168.2.106\r\n\r\n\r\n";
                char response[strlen(page) + strlen(hostString) + 1];
                strcpy(response, page);
                strcat(response, hostString);
                client.print(response);
                //client.print(page);
                //client.print("\r\nHost: 192.168.2.106\r\n\r\n\r\n");
                connectLoop = 0;
                while (!client.available())
                {
                        //Serial.println("client not available");
                        connectLoop++;
                        if ( connectLoop > 10000 ) return 1; //timeout if client was not available for long time
                }
                connectLoop = 0;
                while (client.read() > 0)
                {
                        //Serial.println("reading");
                        connectLoop++;
                        if ( connectLoop > 10000 ) return 1; //timeout if reading data took too long
                }
                client.stop();
                Serial.println(millis() - eth_time);
                return 0;
        }
}

In Firefox’s web developer tools I can see only time and the amount of bytes transferred for http request done from my PC and not from arduino. And in this case it take 2ms / 224B transferred when using my pc.

Generally you should use micros() for timing:

                const unsigned long startTimestamp = micros();
                const char hostString[] = "\r\nHost: 192.168.2.106\r\n\r\n\r\n";
                char response[strlen(page) + strlen(hostString) + 1];
                strcpy(response, page);
                strcat(response, hostString);
                client.print(response);
                //client.print(page);
                //client.print("\r\nHost: 192.168.2.106\r\n\r\n\r\n");
                const unsigned long endTimestamp = micros();
                Serial.println(endTimestamp - startTimestamp);

There's some overhead to assemble the string in memory so you might try the 2 packet alternative also to see which is faster. I haven't tested this code, it's just based on my previous experiences with trying to send as fast as possible with the Ethernet and also ESP8266WiFi libraries.