WiFiServer: Cant read from a raw TCP that stays open and yield (ESP8266)

I am using a NodeMCU8266

My goal:

  • I need to open a TCP port and leave it open.
  • I want to receive data on the TCP port and sometimes respond to that data.
  • When incoming data has been handled I want my ESP8266 to do other stuff.

What I have working already:

Based on sample code for WiFiServer, I am able to listen, and connect, and respond to commands.

The problem is the sample code seems geared up to handling HTTP type requests in which the TCP connection does not persist and it is OK to disconnect after receiving data. The code that handles the incoming data is in a while loop that remains running while the connection is open. Since I want the connect to stay open, this loop never comes to an end, and so the program thus does not yield to anything else. If I change the loop to a simple 'if' (or 'break' after the first command is read in) and do one iteration at a time, no data gets read in! I cannot figure out why.

If I try to change the flow to read data, handle it and then return to the main loop(), the next iteration of the loop causes an exception when I try to obtain the WiFiClient from the WiFiServer. This happens no matter if I call WiFiClient.stop() or not, in the previous iteration.

So here is the code:

#include "ESP8266WiFi.h"
 
const char* ssid = "xxx";
const char* password =  "xxx";
 
WiFiServer RS(50601);
 

void handleRS(WiFiClient rsclient, String line) {  // WiFiClient is passed in so we can send data back to it
  Serial.println(line);
  rsclient.println("{MSG}" + line);  // just echo it back for now
}

void setup() {
 
  Serial.begin(115200);
 
  // get onto wifi
  Serial.println("Connecting");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(250);
    Serial.print(".");
  }
  Serial.print("\nConnected to WiFi. IP:");
  Serial.println(WiFi.localIP());

  // start server listening 
  RS.begin();
}
 
void loop() {

  WiFiClient client = RS.available(); // Doc: Gets a client that is connected to the server and has data available for reading.
                                      //      The connection persists when the returned client object goes out of scope
   
   if (client) {                      // Doc: if no Client has data available for reading, this object will evaluate to false in an if-statement
      // Doc: client.connected() Whether or not the client is connected.
      //      Note that a client is considered connected if the connection has been closed but there is still unread data.
      // next two lines are commented out, showing attempts at not getting stuck in the while loop.
      // if (client.connected() ) {  // fails to read any data in
      // while (client.connected() && client.available()>0) {  // fails to read in data in
      while (client.connected() ) { // works, but since we stay connected, this next while statement traps us there
         if (client.available()>0) { // Doc: Returns the number of bytes available for reading 
            Serial.println(client.available());
            String line = client.readStringUntil('\r');  // read until a carriage return (yup it is in the stream)
            Serial.println(client.available());   // count goes down as expected after the readStringUntil
            handleRS(client,line);  // pretend we handle it
            //break;  // do one line at a time - nope does not work either.
            yield; // not the level of yield I am looking for, I want other code to run
         } // client.available
      } // connected
   } // client

// here is where I want to run other code when data is not arriving on port 50601
Serial.print("x"); we only get here when there is no connection

} // loop()

Any help will be much appreciated.

well, I think I have found the problem…

I declared the client object outside the loop()

WiFiClient client;

and then in the loop():

if (!client) {
    client = RS.available(); // Doc: Gets a client that is connected to the server and has data available for reading.
                                      //      The connection persists when the returned client object goes out of scope
  }

What was happening is that when the loop() iterated, it would reassign the client, and if these was no data awaiting, the client is false, even though still connected!

So now, I only reassign client if it is false - the first time.

If there are better solutions and insight I am keen to hear it!

why not make it local?

or static?

  static WiFiClient client = webServer.available();

  if (!client) {
    client = webServer.available();
  }
  if (!client)
    return;
  if (client.connected()) {

thanks, I will try that. That looks much more elegant.
I am still battling the scoping of C objects.