ESP32 TCP response problem

I've created an TCP server that should response on a certain message by sending some information towards the connected devices. Only i don't receive information every time i send the message.

So i went monitoring and noticed that client.connected does not always return a 1 if i send a message towards the server. It also happends quit often that client.connected sees a 1 and client.available returns a 0, and no message is or will be read. Is there any reason i don't see for this? And how can i fix it?

(If i send a TCP message i receive two messages as usual for the TCP protocol. Only not always with the supposed information that i would expect.)

(here is my code, lot’s of it is for calculating some NTC temps so not relevant for this problem)

#include <WiFi.h>

WiFiServer wifiServer(23);
String Wifi_read;

// Wifi settings
const char *ssid = "ssid";
const char *password = "password";
IPAddress local_IP(10,0,0,93);
IPAddress gateway(10,0,0,138);
IPAddress subnet(255,255,255,0);
int Wifi_led = 2;
int Wifi_status;

// given data
const int ADC_resolution = 4095;
const float VCC = 3.3;

//Settings
int Average_readings = 299; // Starting at 0

//Timers
unsigned long currenttime;
unsigned long nexttime_temps = 0;
int interval_temps = 50;
unsigned long Wifi_nexttime = 0;
int Wifi_interval = 125;
unsigned long check_wifi = 20000;
unsigned long nexttime_WiFi_indication = 0;
int interval_WiFi_indication = 500;

// NTC_1 variables
int NTC_1 = 34;
const int Resistor_1 = 9986;
float ADC_value_1;
float Voltage_1;
float NTC_R_raw_1;
float NTC_R_avg_1;
float NTC_array_1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
int Array_1 = 0;
float T01;
int T01_low;
int T01_high;

// NTC_2 variables
int NTC_2 = 35;
const int Resistor_2 = 9986;
float ADC_value_2;
float Voltage_2;
float NTC_R_raw_2;
float NTC_R_avg_2;
float NTC_array_2[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
int Array_2 = 0;
float T02;
int T02_low;
int T02_high;
float Delta_t;

// values voor lookup table
float value[] = 
{32869, 31229, 29680, 28217, 26834, 25527, 24291, 23122, 22015, 20968,  // 0 t/m 9 degree
19977, 19038, 18149, 17306, 16507, 15750, 15032, 14350, 13703, 13090,   // 10 t/m 19 degree
12507, 11953, 11427, 10927, 10452, 10000, 9570, 9161, 8772, 8402,       // 20 t/m 29 degree
8049, 7713, 7393, 7088, 6798, 6521, 6256, 6004, 5764, 5534,             // 30 t/m 39 degree
5315, 5106, 4906, 4715, 4533, 4358, 4191, 4032, 3879, 3733,             // 40 t/m 49 degree
3594, 3460, 3332, 3210, 3092, 2980, 2872, 2768, 2669, 2574,             // 50 t/m 59 degree
2483, 2396, 2312, 2231, 2154, 2080, 2009, 1940, 1874, 1811,             // 60 t/m 69 degree
1750, 1692, 1636, 1582, 1530, 1480, 1431, 1385, 1340, 1298,             // 70 t/m 79 degree
1256, 1216, 1178, 1141, 1105, 1071, 1038, 1006, 975, 945,               // 80 t/m 89 degree
916, 889, 862, 836, 811, 787, 764, 741, 720, 699,                       // 80 t/m 89 degree
678, 659, 640, 622, 604, 587, 570, 554, 539, 524,                       // 90 t/m 99 degree
509, 495, 481, 468, 455, 443, 431, 419, 408, 397,                       // 100 t/m 109 degree
386, 376, 366, 357, 347, 338};                                           // 110 t/m 115 degree

int value_number;



void setup() { 
  Serial.begin(115200);
  pinMode(Wifi_led, OUTPUT);

  if (!WiFi.config(local_IP, gateway, subnet))  { Serial.println("STA Failed to configure");  }
  
  WiFi.begin(ssid, password);
  wifiServer.begin();
  Serial.println(WiFi.localIP());
}


void loop() {
WiFiClient client = wifiServer.available();
currenttime = millis();
Wifi_labview();

//interval for temperaturs 
if (currenttime >= nexttime_temps)  {
  nexttime_temps += interval_temps;
  Temps();
}

// Interval for wifi_indication
if (currenttime >= nexttime_WiFi_indication)  {
  nexttime_WiFi_indication += interval_WiFi_indication;
  Wifi_indication();
}
}

void Temps() {
  Temps_T01();
  Wifi_labview();
  Temps_T02();
  Wifi_labview();
  Temps_Delta_t();
  Wifi_labview();
}

void Temps_T01()  {
// T01
  // Reading the analog value
  ADC_value_1 = analogRead(NTC_1); // Reading the ADC value
  Voltage_1 = (ADC_value_1 * VCC) / ADC_resolution;
  NTC_R_raw_1 = Resistor_1 / (VCC - Voltage_1) * Voltage_1;

  // Smoothing the resistance value 
  NTC_array_1[Array_1] = NTC_R_raw_1;
  Array_1 += 1;
  if (Array_1 > Average_readings) {Array_1 = 0;}
  NTC_R_avg_1 = 0;
  for (int i = 0; i < Average_readings;)  {
    NTC_R_avg_1 += NTC_array_1[i];
    i++;
  }
  NTC_R_avg_1 = NTC_R_avg_1 / Average_readings;
  if (NTC_array_1[Average_readings] == 0 or NTC_R_raw_1 <= 500) { NTC_R_avg_1 = 0; }
  
  // making an temperatur with decimals 
  value_number = 0;
  while (value[value_number] >= NTC_R_avg_1) {
    T01_low = value_number;
    value_number++;
  }
  T01_high = value_number;
  T01 = T01_low + (1 - ((T01_high - T01_low) / (value[T01_low] - value[T01_high]) * (NTC_R_avg_1 - value[T01_high])));
}

void Temps_T02()  {
// T02
  // Reading the analog value
  ADC_value_2 = analogRead(NTC_2); // Reading the ADC value
  Voltage_2 = (ADC_value_2 * VCC) / ADC_resolution;
  NTC_R_raw_2 = Resistor_2 / (VCC - Voltage_2) * Voltage_2;

  // Smoothing the resistance value 
  NTC_array_2[Array_2] = NTC_R_raw_2;
  Array_2 += 1;
  NTC_R_avg_2 = 0;
  if (Array_2 > Average_readings) {Array_2 = 0;}
  for (int i = 0; i < Average_readings;)  {
    NTC_R_avg_2 += NTC_array_2[i];
    i++;
  }
  NTC_R_avg_2 = NTC_R_avg_2 / Average_readings;
  if (NTC_array_2[Average_readings] == 0 or NTC_R_raw_2 <= 500) { NTC_R_avg_2 = 0; }
  
  // making an temperatur with decimals 
  value_number = 0;
  while (value[value_number] >= NTC_R_avg_2) {
    T02_low = value_number;
    value_number++;
  }
  T02_high = value_number;
  T02 = T02_low + (1 - ((T02_high - T02_low) / (value[T02_low] - value[T02_high]) * (NTC_R_avg_2 - value[T02_high])));
}

void Temps_Delta_t()  {
//Calculating Delta T
  Delta_t = T01 - T02;
}

void Wifi_indication()  {
// Wifi indication led
  if (WiFi.status() != WL_CONNECTED and currenttime >= Wifi_nexttime) {
      Wifi_nexttime = currenttime + Wifi_interval;
      if (Wifi_status == HIGH)  { Wifi_status = LOW;  } else {  Wifi_status = HIGH;  }
      Serial.println("Wifi not connected");
    }
   
  if (WiFi.status() == WL_CONNECTED)  {  Wifi_status = HIGH; }
   digitalWrite(Wifi_led, Wifi_status);
   

// Wifi reset if not connected
   if (currenttime > check_wifi and WiFi.status() != WL_CONNECTED)  {
      check_wifi = currenttime + 15000;
      WiFi.disconnect();
      WiFi.begin(ssid, password);
      Serial.println("Restarting wifi connection");
   }
}

void Wifi_labview() {
// Viewing for TCP messages
  WiFiClient client = wifiServer.available();
  if (client.connected() > 0) {
     Serial.print("Client connected: "); Serial.println(client.connected());
     Serial.print("Client available: "); Serial.println(client.available());
    while (client.available() > 0)  {
      char a = client.read();
      Wifi_read += a;
    }
    Serial.print("Readed from client: "); Serial.println(Wifi_read);


// Responding with an message if the message is read
  if (Wifi_read == "Read")  {
    client.print("T01: ");
    client.print(T01);
    client.print("\t");
    client.print("T02: ");
    client.print(T02);
    client.print("\t");
    client.print("DeltaT: ");
    client.println(currenttime);   

    Serial.println("Temps written to client");
    Serial.println("");
  }

  Wifi_read = "";
  Serial.println("");
}
}

in Erhernet library the server doesn't return a new client until the client sends some data.

but on esp8266/esp32 the server returns a client if the client connects. the client must not send anything or can send data later or simply has a gap between connect and first packet send

use
if (client && client.connected() > 0 && client.available() > 0) {

Juraj:
in Erhernet library the server doesn't return a new client until the client sends some data.

but on esp8266/esp32 the server returns a client if the client connects. the client must not send anything or can send data later or simply has a gap between connect and first packet send

Ah so there is a difference between the library's. As you say with an ESP32 i first need to connect to the server. And when I am connected i can send information towards the server and it should respond. Is that correct?

And how would i be able to achieve that, is it possible within the arduino. Or should i do it within the sender for example within Packet Sender, and how can i achieve that then?

Gert-Jan_Snik:
Ah so there is a difference between the library's. As you say with an ESP32 i first need to connect to the server. And when I am connected i can send information towards the server and it should respond. Is that correct?

And how would i be able to achieve that, is it possible within the arduino. Or should i do it within the sender for example within Packet Sender, and how can i achieve that then?

you run the server on the esp32. you ask in the sketch the WiFiServer object if some client is available. it returns the WiFiClient object if some client connected. and the WiFiClient object returns available more the 0, if the client send some data. you can't expect that if the WiFiClient is connected that it already received the data. so if you expect that the client sends the data after it connects, the read from the WiFiClient only after it has data available.

To understand the difference, here is an example. I have a telnet server in my project for debug output. I connect with telnet terminal, but I don't want to send anything to the Arduino. I expect it sends data to the terminal after I connected. With Ethernet I must send at least one char, with esp it starts sending the lines immediately.

Juraj:
you run the server on the esp32. you ask in the sketch the WiFiServer object if some client is available. it returns the WiFiClient object if some client connected. and the WiFiClient object returns available more the 0, if the client send some data. you can't expect that if the WiFiClient is connected that it already received the data. so if you expect that the client sends the data after it connects, the read from the WiFiClient only after it has data available.

To understand the difference, here is an example. I have a telnet server in my project for debug output. I connect with telnet terminal, but I don't want to send anything to the Arduino. I expect it sends data to the terminal after I connected. With Ethernet I must send at least one char, with esp it starts sending the lines immediately.

Uhm so if i send a packet, the server sees that i wane connect. Cause it is connecting at that moment it won't be able to read the packet message (message and connecting is on the same time/ package and the server was busy connecting). So no response information will be send cause the client data haven't been readed. While the client is connected the server can read messages from the client. And properly respond on it. Is that correct? If not please correct me, i really wane know and understand why it isn't working properly.

If above is correct. The following code should work right?

  WiFiClient client = wifiServer.available();
    while (client.available())  {
      char a = client.read();
      Wifi_read += a;
      Serial.print("Readed from client: "); Serial.println(Wifi_read);
    }
    


// Responding with an message if the message is read
  if (Wifi_read == "Read")  {
    client.print("T01: ");
    client.print(T01);
    client.print("\t");
    client.print("T02: ");
    client.print(T02);
    client.print("\t");
    client.print("DeltaT: ");
    client.println(currenttime);   

    Serial.println("Temps written to client");
    Serial.println("");
  }

  Wifi_read = "";

Gert-Jan_Snik:
Uhm so if i send a packet, the server sees that i wane connect. Cause it is connecting at that moment it won't be able to read the packet message (message and connecting is on the same time/ package and the server was busy connecting). So no response information will be send cause the client data haven't been readed.

in TCP first the connection is established only after then data are exchanged

Gert-Jan_Snik:
While the client is connected the server can read messages from the client. And properly respond on it. Is that correct? If not please correct me, i really wane know and understand why it isn't working properly.

the server creates a server side socket (wrapped in WiFiClient in Arduino). then the sockets are peers. it is not important which one initiated the connection. what you write into one you read from the other.

Gert-Jan_Snik:
If above is correct. The following code should work right?

  WiFiClient client = wifiServer.available();

while (client.available())  {
     char a = client.read();
     Wifi_read += a;
     Serial.print("Readed from client: "); Serial.println(Wifi_read);
   }

// Responding with an message if the message is read
 if (Wifi_read == "Read")  {
   client.print("T01: ");
   client.print(T01);
   client.print("\t");
   client.print("T02: ");
   client.print(T02);
   client.print("\t");
   client.print("DeltaT: ");
   client.println(currenttime);

Serial.println("Temps written to client");
   Serial.println("");
 }

Wifi_read = "";

the problem of the code above is that you take a reference to the socket with local WiFiClient object, but this object is destroyed at the end of the function and the destructor closes the connection as you would call client.stop(). I think it is a design flaw of the library. My workaround is to make the client variable static, but then you must call client.stop() after you finished with the client (read all the data)

  static WiFiClient telnetClient = telnetServer.available();
  if (!telnetClient) {
    telnetClient = telnetServer.available();
  }
  if (telnetClient) {
    if (telnetClient.connected()) {
      while (telnetClient.available()) {
         //read the data
      }
      telnetClient.stop(); // we are finished with this client
    }
  }

or a version to hold the connection open until the terminal disconnects

  static WiFiClient telnetClient = telnetServer.available();
  if (!telnetClient) {
    telnetClient = telnetServer.available();
  }
  if (telnetClient) {
    if (telnetClient.connected()) {
      while (telnetClient.available()) {
         //read the data
      }
    } else { // not connected
      telnetClient.stop(); // cleanup if the other side disconnected
    }
  }

and you have WiFiClient client = wifiServer.available(); in the loop(). it throws away client connections attempts

Thanks for the information. I've tested your code an the version with the hold connection open until the terminal disconnect seems to work as i expected.

Code i'm currently using

void TCP_labview() {
static WiFiClient telnetClient = telnetServer.available();
if (!telnetClient) {  telnetClient = telnetServer.available();  }

// look for data
  if (telnetClient) {    
      if (telnetClient.connected()) { 
          while (telnetClient.available()) {
          char a = telnetClient.read();
          Telnet_readed_data += a;
          } 
  
// Responding with an message if the message is read
{             if (Telnet_readed_data == "Read")  {
                  telnetClient.print("T01: ");
                  telnetClient.print(T01);
                  telnetClient.print("\t");
                  telnetClient.print("T02: ");
                  telnetClient.print(T02);
                  telnetClient.print("\t");
                  telnetClient.print("DeltaT: ");
                  telnetClient.println(Delta_t);   
                  Telnet_readed_data = "";
                  Serial.println("data written to client");
                  }
                  else  { Telnet_readed_data = ""; }
} 
  }
  else { telnetClient.stop();  }
  }
}