ESP 32 wifi client.write() buffer size, unexpected disconnetion of a client

Hallo,
I am trying to send bigger chunks of data over wifi with esp32 using arduino IDE. The simplified code of a server that sends data to a client is:

#include <WiFi.h>

N = 515;
client1 = server.available();


if(client1){
   while(client1.connected()){
     Serial.println("Sending data ...");
      client1.write( (uint8_t *)x, N*sizeof(int));
      client1.write( (uint8_t *)y, N*sizeof(int));
      client1.write( (uint8_t *)z, N*sizeof(int));
   }
    client1.stop();
    Serial.println("Client disconnected.");
    Serial.println("");t
}

The first problem is, that the execution of the code freezes - "Sending data" is not repeatedly displayed in serial monitor and the client does not obtain any data. I suspect that the buffer for sending of the data gets full.

My questions are:

  1. What causes freezing of execution of the code?
  2. What is the default size of the buffer? Can it be increased manually?

The second problem is, when the client closes its communication unexpectedly - tested when client runs out of power. The above mentioned code on server then still expects, that the client is connected - the while(client1.connected()) loop still runs.

My question is:

  1. How can I check on a server, that client have not closed its connection unexpectedly. For example because of poor connection or power off of client's device.

Any help is kindly appreciated!
Thanks

The simplified code of a server that sends data to a client is:

No, that code doesn't compile.

  1. What causes freezing of execution of the code?

Maybe the reason is in that part of the code you're hiding from us.

  1. What is the default size of the buffer? Can it be increased manually?

There might be some buffer but that's in the firmware of the ESP32. I doubt that the buffer runs over as I expect the firmware to send out packets as soon as the packet size is reached.

What kind of client is connecting to your server?

The second problem is, when the client closes its communication unexpectedly - tested when client runs out of power. The above mentioned code on server then still expects, that the client is connected - the while(client1.connected()) loop still runs.

How do you know if the code freezes there?

  1. How can I check on a server, that client have not closed its connection unexpectedly. For example because of poor connection or power off of client's device.

Using the client.connected() call. But the server might need some time to realize that the client is gone if the client not actively terminated the connection.

Hi pylon,
thank you for your reply.

My fault, I should have posted the minimal example. I have worked it out and the freezing disappeared. So the cause is somewhere in the code that I have not posted, as you expected. Not in the size of the buffer. I will go through the code again and try to find out what's wrong.

No, that code doesn't compile.

Maybe the reason is in that part of the code you're hiding from us.

How do you know if the code freezes there?

The client is ESP32. It just connects to the ESP32 server and downloads the data. The codes for the client and for the server are below.

What kind of client is connecting to your server?

Code of the client:

#include <WiFi.h>
#include <WiFiMulti.h>

#define N 512

WiFiMulti WiFiMulti;

const char* ssid     = "ESP32-Access-Point";
const char* pass = "ESP-COME-1";

int status = WL_IDLE_STATUS;
IPAddress myIp;
IPAddress server(192,168,1,1);

// Initialize the client library
WiFiClient client;

int rec [N];
int i (0);

long cas1;
long cas2;

void setup() {
  
  Serial.begin(9600);
  Serial.println();
  Serial.println();
  Serial.println("Attempting to connect to WPA network...");
  Serial.print("SSID: ");
  Serial.println(ssid);
  delay(10);
 
  WiFiMulti.addAP(ssid, pass);

  while(WiFiMulti.run() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
  }

  Serial.println("Connected to wifi");
  Serial.println("\nStarting connection...");
  // if you get a connection, report back via serial:

  if (client.connect(server, 80)) {
     Serial.println("connected");

     myIp = WiFi.localIP();
     Serial.println(myIp);
  }

}

void loop() {
  // put your main code here, to run repeatedly:
  float Dt;
  
    cas1 = micros();
    while(client.available()){
      while(client.available() >= N*sizeof(int)){
            client.read((uint8_t *)rec, N*sizeof(int));
            //Serial.println("Data received");
            //++i;
      }
      delay(1);
    }
    cas2 = micros();
    Dt = (cas2-cas1)/1000.f;
    
    if(Dt>0.1){
      Serial.print("Data transfer time = ");
      Serial.println(Dt); 
    }
}

Code of the server:

#include <WiFi.h>

#define N 512

WiFiServer server(80);
WiFiClient client1;

IPAddress serverIp(192, 168, 1, 1);
IPAddress NMask(255, 255, 255, 0);

const char* ssid = "ESP32-Access-Point";
const char* pssw = "ESP-COME-1";


int x [N];
int y [N];
int z [N];

long time1;

void setup(){
  int k;
  IPAddress IP;

  Serial.begin(9600);                 // Start the serial terminal

  //*************************** WiFi ***************************
  // Connect to Wi-Fi network with SSID and password
  Serial.println("Setting AP (Access Point)…");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, pssw);
  Serial.println("Wait 100 ms for AP_START...");
  delay(100);

  Serial.println("Set softAPConfig");
  WiFi.softAPConfig(serverIp, serverIp, NMask);

  IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
  
  server.begin();
  
  for(k=0;k<N;++k){
    x[k] = 2*k;
    y[k] = 2*k + N;
    z[k] = 2*k + 2*N;  
  }

  time1 = millis();
}

void loop(){
  client1 = server.available();
  
   if (client1) {                             // If a new client connects,
    Serial.println("!....New Client...!");          // print a message out in the serial port
    while (client1.connected()) {            // loop while the client's connected
      
      
      // odeslani dat klientovi po naplneni pole
      if(millis() - time1 > 1000){
        Serial.println("Sending data to the client");
               
        time1 = millis();
       
        client1.write( (uint8_t *)x, N*sizeof(int));
        client1.write( (uint8_t *)y, N*sizeof(int));
        client1.write( (uint8_t *)z, N*sizeof(int));
      }
    }
    client1.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
   }
   else{
    Serial.println("Waiting for a client ...");
    delay(500);
   }
}

With the codes above, when the client is disconnected from a power, the server does not disconnect the client and write neither "Waiting for the client" nor "Client disconnected.". Last output of my serial monitor is: Sending data to the client.

So the problem with unexpected disconnection of the client remains. Do you have any suggestion, how to fix it?

Using the client.connected() call. But the server might need some time to realize that the client is gone if the client not actively terminated the connection.

It's a bad idea to use port 80 if you're not serving HTTP.

With the codes above, when the client is disconnected from a power, the server does not disconnect the client and write neither "Waiting for the client" nor "Client disconnected.". Last output of my serial monitor is: Sending data to the client.

It will tell you "Client disconnected" but that will need quite a long time (I don't know what the standard timeouts on the ESP is but expect at least 3 minutes).
If you disconnect power from the client it has no chance to finish the connection. So the server has to wait for a long time to be sure enough the client doesn't exist anymore and it doesn't just see a temporary problem in the network.

So the problem with unexpected disconnection of the client remains. Do you have any suggestion, how to fix it?

Establish a protocol. Send short packets of data. If the client doesn't acknowledge them within some time frame, expect it to be dead.

Why is it unsuitable? Which port should I use?

It's a bad idea to use port 80 if you're not serving HTTP.

Correct me If I am wrong, but acknowledgement of received data (from side of a client) should be a part of the communication protocol. Therefore, this property (if acknowledgement has been received by the server or not) can be theoretically accessed through WiFi library. Do you know how this can be done?

If not, It can be worked out by common member functions read(), write() between client and server.

Establish a protocol. Send short packets of data. If the client doesn't acknowledge them within some time frame, expect it to be dead.

You might use the forum search function for "server timeout" and "client timeout" to see if there have been disconnect solutions posted in the past.

Hi Zoomkat,
thank you for following up. I will try that.

Why is it unsuitable? Which port should I use?

Because port 80 is reserved for HTTP traffic. As you don't use any known protocol I suggest to use one of the non-privileged ports above 1024.

Correct me If I am wrong, but acknowledgement of received data (from side of a client) should be a part of the communication protocol.

Correct, but you don't use any communication protocol.
The used TCP (the transport protocol) provides means to ensure the data is transferred and in the right order. But that uses it's one timeouts and as far as I know you cannot change these parameters on the ESP32 platform.

"Because port 80 is reserved for HTTP traffic. As you don't use any known protocol I suggest to use one of the non-privileged ports above 1024."

Hmmm..., is there really any practical difference between say port 80 and port 81 other than port 80 being considered the default http operating port and not requiring the port number to be included in a URL? I always use port 80 when possible for simplicity sake.

Hi,
I have solved the issue with timeouts by sending data from a client to a server each second. If the server does not get any data from the client for more than 3 seconds, the client is disconnected. I have implemented this by means of client.read(), client.write() and client.available() functions.

The default timeouts (in WiFi library) from the client's side appear to be shorter than from side of the side of the server. This means, if the connection between client and server is lost, the client closes its connection in few seconds. While the sever maintains the connection of the client at least a few tens of seconds.

I will change the port for convenience.

Because port 80 is reserved for HTTP traffic. As you don't use any known protocol I suggest to use one of the non-privileged ports above 1024.

Thanks for comments a help pylon and zoomkat.

Hmmm..., is there really any practical difference between say port 80 and port 81 other than port 80 being considered the default http operating port and not requiring the port number to be included in a URL? I always use port 80 when possible for simplicity sake.

No, there isn't. But it's like using a black wire for GND and a red one for Vcc. The circuit won't complain if you use other colors but there good reasons to do it right.