Smartphone -> Arduino Ethernet Server

The Ethernet Server example works fine with the standard delay(1) before client.stop() on fast internet connections such as Ethernet, DSL,...
But my problem is: when i want to connect from smartphone to the arduino (e.g.via dyndns), the html page is transmitted broken.Only if i change to delay(3000) or higher, i get the complete page.

Is there any way, the arduino can determin, whether the page has been completely transmitted ?

The "delay method" doesn't seem to be very stable with low transmission rates.

Is there any better way ???

The "delay method" doesn't seem to be very stable with low transmission rates.

It's not even a good idea at very high speeds.

Is there any way, the arduino can determin, whether the page has been completely transmitted ?

Of course. The client() connected method will return false when the server closes the connection AND all the client data has been read. So, in a while(client.connected()) loop, use a while(client.available() > 0) loop to read all the data. When the inner loop has read all the data, the outer loop will, eventually, return false because all the data has been sent AND read.

The delay() is not necessary. This is TCP, not UDP. The server must wait for a ACK for the last packet before closing the connection. Read this topic:
http://arduino.cc/forum/index.php/topic,122784.0.html
There is a link to my server code there that is the code he pounded with 1000's of requests. No fails there.

in a while(client.connected()) loop, use a while(client.available() > 0) loop to read all the data

That's exactly my code. But the problem still exists: In case of a verry slow internet connection such as gsm, the server closes the connection, BEFORE the client has read all data.
Which means: client.connected() returns false even not all data is read.

Just try !

I which i had a better mthod than "delay(3000)" to work arround that behavior !

That is exactly your code? You are using my server code?

If the server closes the connection, it is finished sending packets, and the receiver says it emptied its rx buffer (sent an ACK) after the last packet the server sent to the client.

If the connection breaks (not closed by the server) you will get no close/stop message, and the connection will stay open forever. I use a 10 second timeout with my server code to determine if the connection has failed.

Maybe it's another problem too: I want to client.println about 80 lines before connection is be closed. Is that to much for the W5100's buffer ?
Does the ethernet library prevent buffer overflow's of the W5100 ?

I just checked my server code on my Crackberry thru Verizon 3G, and it did fine. Tried a couple form entries, and all worked well.

I avoid using too many client.print client.println, and client.write calls. Each generates another packet. Best to use sprintf and a character array. Then send the whole thing at once.

thru Verizon 3G

a 3G network isn't "slow". i meant pure gsm ! on 3G i believe everything works fine.

I think you are right by avoiding client.print, etc. . But how to pack a ton of html in a character array ???
With client.print(" i can use copy and paste from the an editor.
Does client.sprintf work ? Didn't see it in the reference. Do have perhaps a piece of code for me ?

Sorry. It was as slow as I could get on my Crackberry. I can really slow stuff up with my router. I'll check at some really slow bandwidths.

This is how I use sprintf.

int x = 4;
int y = 6;
char outBuf[64];

sprintf(outBuf,"x=%d and y=%d",x,y);
client.println(outBuf);

Send in one packet instead of four.

edit: I just tried it with my router throttled to 48k up and down. Speed verified by speedtest.net. Worked fine.

throttled to 48k up and down

48K is far beyond my gsm connection !
Thank you for your code. That speeds up transmission significantly.

But i have a question to the ethernet library: What happens if more data is printed via client.println, sprintf,... than the W5100's buffer can hold ? Is the client.print command blocking further program execution until enough data is read ? I think no.

But what happens to the data, that exceeds the buffer ?

What happens if more data is printed via client.println, sprintf,... than the W5100's buffer can hold ?

Blocking. I think yes. I've tried it.

edit: Here is the request for a new function that would allow the program to determine if the next send will be blocking or not. I thought it was a fail, but if you read comment#1, it was blocking, not failing.
http://code.google.com/p/arduino/issues/detail?id=642

This does not include an attempt to send more in one send (like 2000 characters) than the w5100 tx buffer will hold, but that would exceed the size of a single packet. Not recommended.

If your device cannot handle 48k bandwidth, maybe you should get a "smarterphone". :wink:

I've tested Blackberry, IPhone, IPad, and Android. All worked.

Thank you very much, Comment #2 says everything: Client.stop() dropps the connection to early when transmitting a large amount of data or the connection is slow.

I propose the following solution:

while (W5100.getTXFreeSize(_sock) < 2048) {

  • // time out handling should be implemented here !* };
    client.stop();

This gives the W5100 time to send all data. Works fine and much more stable than the "delay(1)" method.

edit: my good old win mobile 6.5 smartphone is fast enough for me, the problem is the gsm net (pure gsm: 14K under good conditions)

If your code needs that check, something else is wrong. The w5100 should not close the connection until the client has sent an ACK for the last packet sent, not the next packet in the tx buffer.

Maybe there is still a bug lurking in the library, but I can't slow up my equipment that much to cause a fail. 48k took forever to download the speedtest.net webpage.

I think I found your challenge. The stop function will attempt to close the connection gracefully for one second, then it will force a close, no matter what is left in the tx buffer.

Maybe that function to check the tx buffer I submitted is needed more than wanted.

edit: If you want to change that value, it is in EthernetClient.cpp
void EthernetClient::stop()

Look for the comment "wait a second for the connection to close". Change 1000 to 3000 (or more for you). If you change that value, it will wait the three seconds only if the connection is slow. Your change with the delay(3000) would apply to all connections, slowing up stuff that shouldn't be.

Great !
That's it !