Webserver unresponsive when more than 1 tcp connection is made

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

byte mac[] = {  0x90, 0xA2, 0xDA, 0x00, 0xCD, 0x3E };  //Set your Ethernet Shield's MAC address
byte ip[] = {  192,168,1,131 };    // Set your shield's  IP address
byte gateway[] = {  192,168,1,1 };   //if you need  a gateway IP
byte subnet[] = { 255,255,255,0 };    // Change  to your subnet address

  
EthernetServer  server(85);                // server port 

// declare variables

int     ledPin = 6;                // LED1 
int     heatpin = 7;               // ANTENNA
int     aedpin = 5;                // LED3  
int     fedpin = 8;                // fE PWR 
int     medpin = 9;                // me - anolog pin 9 for fan control
int     sensorPin = A0;            // analog in 0 forlight sense
int     sensorValue = 0;           // integer for the analog sensor
int     PIRstate = 0;              // variable for PIR sensor status
int     PIR = 2;                   // PIR sensor is connected to digital pin 2
int     motorlevel = 0;                // motor
String  readString = String(30);   // string for fetching data from address
boolean LEDON = false;             // LED1 status flag
boolean HEDON = false;             // ANTENNA status flag  
boolean AEDON = false;             // led3 status AE



 
// SETUP NOW

void setup()
{    
  
  Ethernet.begin(mac, ip, gateway, subnet ); //start Ethernet
  server.begin();  //test
  
  
  pinMode(ledPin, OUTPUT); //Set pin 6 to output
  pinMode(heatpin, OUTPUT); // set pin 7 to output
  pinMode(aedpin, OUTPUT); // set pin 5 to output
  pinMode(fedpin, OUTPUT); // set pin 8 to output
  pinMode(PIR, INPUT); // set pir to input
  pinMode(medpin, OUTPUT); // set pin a3 to output
  byte client_ip[4];
   
  sensorValue = analogRead(sensorPin);
  }

void loop(){
 
  EthernetClient client = server.available();  // Create a client connection
  
  if (client) {
    boolean current_line_is_blank = true; //new
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if we've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // send a reply
        
        if (readString.length() < 30) { //read char by char HTTP request
          readString.concat(c); 
        } //store characters to string

        
// HTML Code  

if (c == '\n' && current_line_is_blank) {
          
          // HTML Code
          client.println(F("HTTP/1.1 200 OK")); //output HTML data starting with standard header
          client.println(F("Content-Type: text/html"));
          client.println();
          client.print(F("<body style=background-color:BLACK>")); //set background to BLACK
          // Auto refresh webpage every 60 seconds
          client.println(F("<META HTTP-EQUIV=REFRESH CONTENT=60 URL=>"));
          client.println("<center>");
          client.println(F("<font color=’green’><h1>INTERNET -- CONTROL </font></h1>/"));//send first heading
          client.println(F("<hr />"));
          client.println(F("<font color=’#0D8112’ size=’5?> "));
          client.println("</center>");
          motorlevel = 0;
      }       
  
           //indexOf("L=")

        if (c == '\n') { //if HTTP request has ended

          int Le = readString.indexOf("L="); //here is a key component of where
          int He = readString.indexOf("H="); //the status is being read by the arduino
          int Ae = readString.indexOf("A=");
          int Fe = readString.indexOf("F=");
                 
          // Check if anything  should be lighted or turned on
                          
                 
            if (Le > 1){

            if (readString.substring(Le,(Le+3)) == "L=1") { //led has to be turned ON
              digitalWrite(ledPin, HIGH); // set the LED on
              
              LEDON = true;
            }

            if (readString.substring(Le,(Le+3)) == "L=0") {
              //led has to be turned OFF
              digitalWrite(ledPin, LOW); // set the LED OFF
              
              LEDON = false;
            }
          }

          if (Fe > 1){

            if (readString.substring(Fe,(Fe+3)) == "F=1") { //PWR  has to be turned ON
              digitalWrite(fedpin, HIGH); // set the PWR on
              
              FEDON = true;
            }

            if (readString.substring(Fe,(Fe+3)) == "F=0") { //PWR has to be turned OFF
              digitalWrite(fedpin, LOW); // set the PWR OFF
              
              FEDON = false;
            }
          }
                        
          sensorValue = analogRead(sensorPin);

          // detemine / print is room is dark or light
          

          client.print(sensorValue);   //  a test to see the photo sensor value

          if (sensorValue < 550) {
            client.println( F("<center><font color ='deepskyblue' >THE ROOM IS NOW - *DARK* - </font></center>") );
          }
          
          else {
            client.println( F("<center><font color ='gold' >THE ROOM IS NOW  - *BRIGHT* -  </font></center>") );
          }
                  
          client.println(F("<hr />"));
                         
          client.println(F("<center></center>"));
          client.println(F("<font color=’green’> </font>"));
          client.println("<center>");{
          client.println(F("<form  method=get name=LED>"));
          client.println(F("<button name=F value=1 type=submit style=height:100px;width:130px>PWR On</button>"));
          client.println(F("<button name=F value=0 type=submit style=height:100px;width:130px>PWR Off</button>"));
          client.println(F("</form>
"));
          client.println(F("<hr />"));
          client.println("</center>");
           client.print(F("<form method=get name=LED>"));
           client.print(F("<input type='radio' name='A' value='1'>LED3 ON
"));
           client.print(F("<input type='radio' name='A' value='0'>LED3 OFF

"));
           client.println(F("<input type=submit value=submit></form>"));
           client.println(F("<hr />"));
                                     
           }
          // DETERMINE WHAT STATUS TO PRINT  
         
          client.print(F("<font size=’5?>LED1 status: "));
          if (LEDON == true) {
            client.println(F("<font color='#FF0000' size=’5?>ON</font>")); //red

          }
          else {
            client.println(F("<font color='#0099FF' size=’5?>OFF</font>")); //blue

          }
          client.println(F("
"));
          
          //printing ant status
          
          client.print(F("<font color='#00B200'>ANT status: ")); //green
          if (HEDON == true) {
            client.println(F("<font color='#FF0000' size=’5?>ON</font>")); //red
           
          }
          else {
            client.println(F("<font color='#0099FF' size=’5?>OFF")); //blue
            
          }
          client.println(F("
"));
          
          //printing AEant status
          
          client.print(F("<font size=’5? font color='#00B200'>LED3 status: ")); //green
          if (AEDON == true) {
            client.println(F("<font color='#FF0000' size=’5?>ON")); //red
            //  Serial.print("LED3 on");
          }
          else {
            client.println(F("<font color='#0099FF' size=’5?>OFF"));//blue
           
          }
          client.println(F("
"));

          
          // WEB PAGE Footer
          
          client.println(F("<hr><center><a href=http://xxxxxx:xxx>WEBPAGE</a>
"));
          client.println(F("<p><font color=darkcyan>This Page  Will Refresh Every 60 seconds.</font></center>"));
          
         
          client.println(F("<hr />"));
          client.println(F("</body></html>"));


          readString=""; 
          delay(2); 
          client.stop(); //stopping client
          client.flush();
        }
      }
    }
  }
}

I have a working Arduino web server which serves an html web page allowing me to see the status and to control devices.
If I connect from a single PC it works fine. I can turn devices on and off and see status changes.

If I now go to another PC and connect, it causes the Arduino Webserver to become non responsive.

if i connect on one pc and forget to close the browser and then decide to go connect from another pc - the server will not answer…
Or if i am connected and someone else connects, within a few seconds the server becomes unresponsive

Any suggestions how to fix the problem?

String  readString = String(30);   // string for fetching data from address

Why are you using the copy constructor to initialize readString to “30”?

  byte client_ip[4];

A local variable that almost immediately goes out of scope. How useful is that?

          delay(2);

Why? This just boggles the mind. You are complaining about unresponsiveness, yet you have this useless delay…

Granted it’s not a very long delay, but get rid of it.

I have a working Arduino web server which serves an html web page allowing me to see the status and to control devices.

A very large web page.

          client.println(F("<font color=’green’> </font>"));
          client.println("<center>");{
          client.println(F("<form  method=get name=LED>"));

Why are all strings not in Flash>

What you get from the client is less than 30 characters, right? Why is the overhead of the String class necessary? It fragments memory pretty badly.

http://xxxxx.radxxx.no-p.com:84/?H=1&A=1&F=1&M=1

Code:

String readString = String(30); // string for fetching data from address

Why are you using the copy constructor to initialize readString to “30”?

To ensure i have a string length long enough to read in the client inputs?

Any suggestions?


Code:

byte client_ip[4];

A local variable that almost immediately goes out of scope. How useful is that?

old code - removed it – no changes, same symptoms


Code:

delay(2);

Why? This just boggles the mind. You are complaining about unresponsiveness, yet you have this useless delay…

Granted it’s not a very long delay, but get rid of it.

Removed it - still no change - same symptoms

Quote
I have a working Arduino web server which serves an html web page allowing me to see the status and to control devices.
A very large web page.

Well, I am open to suggestions on how to rework it to make it more efficient, smaller but with the same capabilities


Code:

client.println(F(" “));
client.println(”");{
client.println(F(""));

Why are all strings not in Flash>

If your referring the the client.println(“center”); —oops - I missed one

If not then How would you make it more memory efficient?


What you get from the client is less than 30 characters, right? Why is the overhead of the String class necessary? It fragments memory pretty badly.

This is the possible max length of a client input but could it be even longer

http://xxxxx.radxxxx.no-p.com:84/?H=1&A=1&F=1&M=1

Was trying to ensure i can capture the full length

Any suggestion? to make it work better or without this code

So, far, no change in symptoms withe the new changes

Thanks for the inputs
Joe

To ensure i have a string length long enough to read in the client inputs?

But, the String(int arg) constructor does not allocate space to hold arg characters. It converts arg to a string, and initializes the instance. The assignment to readString then makes a copy.

Any suggestions?

char inData[30];
does allocate space to hold 30 characters, and no re-allocation needs to be done to add a character to the array. Therefore, no memory fragmentation.

Well, I am open to suggestions on how to rework it to make it more efficient, smaller but with the same capabilities

Well, one wonders just how much centering and color and specific font size contribute to the page.

          client.println(F("<center></center>"));

Needed?

I would try adding a Serial.print() statement to print the value of micros() when starting to send the page back, and another to print the value of micros() when done sending the page back, and see just how long it takes to send the page.

The wiznet chip can support 4 simultaneous connections, but the Arduino can only deal with one at a time. If you are spending a lot of time sending a page, and automatically re-sending the page every 60 seconds, there may not be adequate capacity to handle multiple connections.

Does the responsiveness improve if you remove the REFRESH line?

Quote
Any suggestions?
char inData[30];
does allocate space to hold 30 characters, and no re-allocation needs to be done to add a character to the array. Therefore, no memory fragmentation.

Did some looking around on how to implement or replace my current method using char inData[30]; but a search found nothing

Need your assistance on adding this method


Quote
Well, I am open to suggestions on how to rework it to make it more efficient, smaller but with the same capabilities
Well, one wonders just how much centering and color and specific font size contribute to the page.

Code:

client.println(F(""));

Needed?

Ok will try to remove extra formatting to reduce overall file size.


I would try adding a Serial.print() statement to print the value of micros() when starting to send the page back, and another to print the value of micros() when done sending the page back, and see just how long it takes to send the page.

The wiznet chip can support 4 simultaneous connections, but the Arduino can only deal with one at a time. If you are spending a lot of time sending a page, and automatically re-sending the page every 60 seconds, there may not be adequate capacity to handle multiple connections.

Sorry, to be so limited in programming knowledge but not sure how to implement your suggestion monitor micros()? ---- i am very new, and learning piece by piece and its a long learning curve.

An example would be much appreciated

Does the responsiveness improve if you remove the REFRESH line?

I removed / commented it out - still no change - Server will time out if 2 connections are used at the same time - - symptoms the same

SUMMARY:

If I terminate both connections and restart the browser and try to connect - sometimes it will recover and a connection occurs, but most times it times out the browser

It appears to me, the webserver is not releasing the connection completely, or gets confused when more than 1 connection is active.

I was wondering if you would suggest how to force a connection termination after x time? -or if certain condition occurs ?


Thanks
Joe

I was wondering if you would suggest how to force a connection termination after x time?

If you can't even add three lines of code to print the time, how would you implement a forced closing of the connection?

PaulS,

Another thought,

I was wondering if it is possible or easy to add a command which when sent by a web browser would terminate the current TCP connection?

Maybe even add a button on the web page to force an Exit / Close Connection?

Joe

Quote I was wondering if you would suggest how to force a connection termination after x time? If you can't even add three lines of code to print the time, how would you implement a forced closing of the connection?

I can implement limited code and have been able to build a basic server but unfortunately your explanation is not always perfect, so new people who are just learning do miss the simple things.

Joe

I can implement limited code and have been able to build a basic server but unfortunately your explanation is not always perfect, so new people who are just learning do miss the simple things.

Adding an ethernet shield to an Arduino is not a beginner project. It really isn’t even an intermediate project. I consider it an early advanced project.

I expect that by the time you get to the point where you have added an ethernet shield to the Arduino that you are quite adept at using Serial.print() for debugging, so that a mere suggestion to try printing the value returned by micros() is sufficient.

If that is not the case, then I don’t think anything short of “Copy and paste this code” after “this code” will help you.

There are many things that have not been disclosed. How is the Arduino with ethernet shield connected to the network? Does it have a static IP address? Are the other devices on the LAN the ones that are connecting to it? Is there a router involved? Does the router configuration allow multiple connections. Are connections from outside the LAN possible?

Changing the code on the Arduino to deal with multiple connections should not be necessary. Having the Arduino forcibly close an existing connection when a new one occurs is not the solution.

Closing a connection after some period of inactivity might be needed, but how much time is reasonable? Until you can answer that, don’t try to close a connection after a period of time.

Web browsers should be able to deal with a connection that's been closed even when "keep-alive" is TRUE in the request header. I force close connections all the time and browsers manage to deal with it.

Given that the Arduino has such a limited connection capability, I'd force close =all= connections, always. Let the browser create a new one and make it so the Arduino always has as many "free" connections as possible.

PaulS,

Quote I can implement limited code and have been able to build a basic server but unfortunately your explanation is not always perfect, so new people who are just learning do miss the simple things. Adding an ethernet shield to an Arduino is not a beginner project. It really isn't even an intermediate project. I consider it an early advanced project.

I expect that by the time you get to the point where you have added an ethernet shield to the Arduino that you are quite adept at using Serial.print() for debugging, so that a mere suggestion to try printing the value returned by micros() is sufficient.

If that is not the case, then I don't think anything short of "Copy and paste this code" after "this code" will help you.

There are many things that have not been disclosed. How is the Arduino with ethernet shield connected to the network? Does it have a static IP address? Are the other devices on the LAN the ones that are connecting to it? Is there a router involved? Does the router configuration allow multiple connections. Are connections from outside the LAN possible?

Changing the code on the Arduino to deal with multiple connections should not be necessary. Having the Arduino forcibly close an existing connection when a new one occurs is not the solution.

Closing a connection after some period of inactivity might be needed, but how much time is reasonable? Until you can answer that, don't try to close a connection after a period of time.


I admit I am ambitious but it works, minus a few issues its almost done.

Serial print was not the issue, only the micros() command, i had not seen it before and was not clear on how to implement. I even did a search and did not come across any examples

The ethernet shield is stacked on the Arduino and is connected hardwired to a 1gig backbone to a router running Tomato firmware.... works exceptionally well. The Arduino is set for a static ip, and gateway (which is the router ip). It has been port forwarded and I have had people connect to it successfully from around the country. I am also able to connect on my local LAN with numerous computers. The router also has a 1gig lan side all switches are also cat6 1gig speed and all allow many many simultaneous connections with no problems.

I agree, forcing timed a termination - seems drastic but it would ensure if a normal disconnect did not occur then after say 5 minutes and auto disconnect would occur - almost like a tcp connect watchdog

RECAP: When Arduino is connected by a 1 client web browser - it works perfect, fast from internal Lan and just as fast from someone on the internet. Now, when someone else connects (2nd connection) at the same time from Lan or internet --- after operating a few butttons to turn on / off - one or both of the tcp connections will eventually timeout. If i terminate one connection, it may comeback but in most cases, i must terminate both browsers. Of course if someone outside leaves his / her browser connected then I cannot terminate the connect and the Arduino will not respond..

Locally (LAN), if i terminate both browsers,i must wait for a few minutes before it will respond to a new connection. In some cases i must drop the power to the Arduino before it will allow a reconnect.

I have several Arduino's and 2 shields - The behavior is the same on both

I also relocated the Ethernet source to another connection - same no change.

Joe


jfhaugh,

Web browsers should be able to deal with a connection that's been closed even when "keep-alive" is TRUE in the request header. I force close connections all the time and browsers manage to deal with it.

Given that the Arduino has such a limited connection capability, I'd force close =all= connections, always. Let the browser create a new one and make it so the Arduino always has as many "free" connections as possible.

Your approach sound reasonable..

How do you force close connections? - manually or via Arduino code?

I thought these would do that.

client.stop(); //stopping client client.flush();

Or do i use an Ethernet client (close) command of some sort?

Thanks For all the feed back Joe

Server test code with a meta refresh web page. You can load it and then see if you can get the page to refresh on more than just one computer at a time.

// arduino IDE 1.0
// for W5100 ethernet shield
// the IP address will be dependent on your local network/router
// port 80 is default for HTTP, but can be changed as needed
// use IP address like http://192.168.1.102:84 in your brouser
// or http://zoomkat.no-ip.com:84 with dynamic IP service
// use the \ slash to escape the " in the html
// meta refresh set for 2 seconds

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

int x=0; //set refresh counter to 0
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,102); // ip in lan
EthernetServer server(84); //server is using port 84

void setup()
{
  // start the server
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
     while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // see if HTTP request has ended with blank line
        if (c == '\n') {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          
          //meta-refresh page every 2 seconds
          x=x+1; //page upload counter
          client.println("<HTML>");
          client.print("<HEAD>");
          client.print("<meta http-equiv=\"refresh\" content=\"2\">");
          client.print("<TITLE />Zoomkat's meta-refresh test</title>");
          client.print("</head>");
          client.println("<BODY>");
          client.print("Zoomkat's meta-refresh test IDE 1.0");
          client.println("
");
                    
          client.print("page refresh number ");
          client.println(x); //current refresh count
          client.println("
");
          client.println("
");
          
          client.print("Zoomkat's arduino analog input values:");
          client.println("
");
          client.println("
");
          
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(analogRead(analogChannel));
            client.println("
");
            }
           break;
          client.println("</BODY>");
          client.println("</HTML>");
         }
        }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}

zoomkat,

Tried your test code, works perfect

loaded 4 browsers on 3 different computers at the same time for about 15 minutes - all web pages are refreshing, and data was changing

This would seem to appear that my hardware and connectivity are fine but my coding is at fault… I was pretty sure that was the issue - but this confirms it.

Now, what is the best approach to try to isolate my problems.

I posted most of my code but it was to long. So I attached the full code, Hoping some would look and see what i am doing wrong.

Thanks for your input

Joe

webservergreen52test.ino (13.5 KB)

zoomkat,

I compared your code and mine and noticed some differences in the html area and in a few other areas. I made several changes on my server.

Have been testing modified server with 3 LAN connections on different computers turning items on/off and so far it has been working Perfectly!!

Next, will do the same from internet connections ---Looking good

If all goes well I will re post the complete working code for others to play with / learn etc.

ThankYou!


Thanks again to all who responded to my requests. Joe

I made several changes on my server.
Have been testing modified server with 3 LAN connections on different computers turning items on/off and
so far it has been working Perfectly!!

So, what did you change?

PaulS,

I removed:
// boolean current_line_is_blank = true; //new

//indexOf(“L=”)

if (c == ‘\n’) { //if HTTP request has ended // i had this twice,

// HTML Code

// if (c == ‘\n’ && current_line_is_blank) { // removed this

if (c == ‘\n’) { //if HTTP request has ended - replaced with this

I added this:

client.println(F("")); //
client.print(F("")); //

So far, I now can use multiple simultaneous connections.
I am not saying code is still very good and needs more fine tuning, but it appears that this issue is under control…
Trying some more internet connections from different locations…

Joe