TCPClient connected() issues

Hello everyone,

I’ve been running my weather station on 0.4.7 for a little while now and have had some great success keeping it connected now that I am using a u.FL antenna (my record so far is over 1,000,000 seconds - a little over 11.5 days!). Still hasn’t hit -40ºC outside yet, but I’ll leave that test for later…

So I figured it was time to break things again and start playing around :wink:

I’ve been continually working to improve efficiency when working with Weather Underground, and thought to myself – the server seems to support keep-alive, since when I telnet into it I can keep sending push updates and so long as there are updates sent more often than 15s, the connection remains open. This got me to thinking … I’m using a really silly method of connect, println, delay, read, stop (disconnect). If the connection can be persistent, why don’t I just connect, println, delay, read, println, delay, read […] and use a single connection? So I gave it a try.

And for the most part, it works! BUT, there seems to be some weirdness going on. First, some code.

TCPClient client;
char WULastResp[512];
String WULastCmd; // Contains the last GET request sent to Wunderground

volatile bool wuSend;

void cbWUSend() {
  wuSend = true;
}

Timer tWUSend(5000, cbWUSend);

void setup() {
  tWUSend.start();
}

void loop() {
  if(wuSend){ 
    wuSend = false;
    // Read the data returned from the ***LAST*** push! This grants us the maximum allowable delay (by *our* specifications).
    if(client.available()){ // There's data to read!
      int i = 0;
      while (client.available())
      {
          char c = client.read();
          if (i < 512)
              WULastResp[i++] = c;
      }
      Particle.publish("WU-PushSuccess", String::format("Received response from WU: %s", WULastResp), 3600, PRIVATE);
    }
    else if(client.connected()) {
      // WOAH! There's no data after our last push, but we are still "connected"?
      // Looks like the connection stalled! Reconnect.
      client.stop();
      client.flush();
      Particle.publish("WU-NoResponse", "WU never responded before next push! Forcing disconnection before pushing.", 3600, PRIVATE);
    }

    // Connect to WU.
    // We will reach this point on two occasions:
    //  • when there was no data to be read, and the client was still "connected", so we forcefully reset it (above)
    //  • when there was no connection to begin with (initial start-up).
    if(!client.connected()) // THIS IS WHERE SOMETHING ODD OCCURS
    {
      if (!client.connect(SERVER, 80))
      {
        Particle.publish("WU-ConnFailed", "Connection to WU Failed!", 3600, PRIVATE);
      }
      else {
        Particle.publish("WU-ConnSuccess", "Connection to WU Succeeded!", 3600, PRIVATE);
      }
    }
    // Now the client should be connected, either because we just connected above, or it
    // was already connected when this loop started. But we just make sure…
    if(client.connected()){
      Particle.publish("WU-TryingPush", "Everything is connected, trying data push!", 3600, PRIVATE);
      sendToWU(); // this calls client.println() after assembling a string to send, nothing more, nothing less.
    }
    else {
      Particle.publish("WU-NotConnected", "Connection to WU didn't establish before push!", 3600, PRIVATE);
    }
  }
}

Let’s have an example now of what my event log looks like.

event: WU-ConnSuccess
data: {"data":"Connection to WU Succeeded!","ttl":"3600","published_at":"2015-11-28T05:09:59.391Z","coreid":""}

event: WU-TryingPush
data: {"data":"Everything is connected, trying data push!","ttl":"3600","published_at":"2015-11-28T05:09:59.470Z","coreid":""}

event: WU-PushSuccess
data: {"data":"Received response from WU: HTTP/1.0 200 OK\r\nContent-type: text/html\r\nDate: Sat, 28 Nov 2015 05:09:59 GMT\r\nContent-Length: 8\r\n\r\nsuccess\n","ttl":"3600","published_at":"2015-11-28T05:10:04.230Z","coreid":""}

event: WU-ConnSuccess
data: {"data":"Connection to WU Succeeded!","ttl":"3600","published_at":"2015-11-28T05:10:04.800Z","coreid":""}

event: WU-TryingPush
data: {"data":"Everything is connected, trying data push!","ttl":"3600","published_at":"2015-11-28T05:10:04.881Z","coreid":""}

event: WU-PushSuccess
data: {"data":"Received response from WU: HTTP/1.0 200 OK\r\nContent-type: text/html\r\nDate: Sat, 28 Nov 2015 05:10:04 GMT\r\nContent-Length: 8\r\n\r\nsuccess\n","ttl":"3600","published_at":"2015-11-28T05:10:09.228Z","coreid":""}

What I don’t understand is why it is reconnecting every time? I never call client.stop(). I should only be seeing my WU-ConnSuccess event once, when the connection is opened, but instead, It looks like if(!client.connected()) is somehow indicating that there is no connection, when in fact there should be one - and another connection is made each time.

Is the connection automatically considered “disconnected” if there is no more data to read? That’s the only thing I can think of! Comments and suggestions appreciated! I know @mdma and others did a bunch of TCPClient bug-fixing work on 0.4.4, perhaps intimate knowledge of this system can help explain what’s going on here :wink:

When the remote server closes the connection then connected() will return false.