Link to a very basic tutorial about TCP (evolved to: TCP-socket democode to send / receive data / characters similar to serial

I've got the AsyncTCP library @Juraj suggested in post #25 working. I have code for my project doing what I want and working reliably, and I made a simplified version of the client code, posted below. This pretty much does the same as the client code in post #8 but uses the AsyncTCP library. As this uses the AsyncTCP library it is non-blocking, leaving other code on the ESP8266 to carry on doing its thing regardless of what happens to the client-server connection. There is a 5 second timeout, which monitors for a reply from the server, if there is no reply in 5 seconds it attempts to reconnect to the server. The server is the same as the server code in post #8; I have not made new server code based on the AsyncTCP library. Enjoy.

// https://forum.arduino.cc/t/link-to-a-very-basic-tutorial-about-tcp/949935

// Demonstration code to transfer data from server to client using AsyncTCP, which is non-blocking
// This code sends a 'request' in for form of a single character to the corresponding server, which responds with the value of Millis

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>

#define STASSID "Put your WiFi SSID here"
#define STAPSK  "Put your WiFi password here"

const char * ssid = STASSID;
const char * pass = STAPSK;
IPAddress serverIP(192, 168, 2, 62);
#define portNumber 7005
#define NUM_CLIENTS 2
#define CLIENTTIMEOUT 5
AsyncClient* clients[NUM_CLIENTS];
uint8_t timeout[NUM_CLIENTS];

const IPAddress addresses[NUM_CLIENTS] = {{192,168,2,62}, {192,168,2,62}}; // IP addresses of the servers, both the same here but can be different. Change to use the IP address(s) where your server is to be found.

void setup_serial_port();
void setup_wifi();
void setupClients();

void setup() {
    setup_serial_port();
    setup_wifi();
    setupClients();
}

void loop() {
    everySecond();
}

void everySecond() {
    uint32_t currentMillis = millis();
    static uint32_t lastMillis;
    const uint32_t waitTime = 1000;    
    if (currentMillis - lastMillis >= waitTime) {
        lastMillis += waitTime;
        if (timeout[0]) {
            --timeout[0];
        }
        if (timeout[1]) {
            --timeout[1];
        }
        TCP_Client(0);
        TCP_Client(1);
    }
}

void TCP_Client(uint8_t clientIndex) {
    static uint8_t state[NUM_CLIENTS];
    enum states {notConnected, Connecting, Connected};
    char message[32];
    
    Serial.print("State = ");
    Serial.println(state[clientIndex]);
    
    if (clientIndex < NUM_CLIENTS) {
        switch (state[clientIndex]) {
            case notConnected:
                if (clients[clientIndex]->connected()) {
                    timeout[clientIndex] = CLIENTTIMEOUT;
                    state[clientIndex] = Connected;
                } else {
                    clients[clientIndex]->connect(addresses[clientIndex], portNumber);
                    timeout[clientIndex] = CLIENTTIMEOUT;
                    state[clientIndex] = Connecting;
                }
                break;
            case Connecting:
                if (clients[clientIndex]->connected()) {
                    timeout[clientIndex] = CLIENTTIMEOUT;
                    state[clientIndex] = Connected;
                } else if (!timeout[clientIndex]) {
                    state[clientIndex] = notConnected;
                }
                break;
            case Connected:
                if (clients[clientIndex]->connected()) {
                    if (timeout[clientIndex]) {
                        sprintf(message, "T");
                        clients[clientIndex]->add(message, strlen(message));
                        clients[clientIndex]->send();  
                    } else {
                        Serial.print("Client ");
                        Serial.print(clientIndex);
                        Serial.println(" timed Out");
    
                        clients[clientIndex]->stop();
                        
                        timeout[clientIndex] = CLIENTTIMEOUT;
                        state[clientIndex] = notConnected;
                    }
                } else {
                    state[clientIndex] = notConnected;
                }
                break;
        }
    }
}

/* event callbacks */
static void handleData(void* arg, AsyncClient* client, void *data, size_t len) {
    //Serial.printf("data received from %s\n", client->remoteIP().toString().c_str());
    if (client == clients[0]) {
        Serial.print("Data from client 0 ");
        Serial.write((uint8_t*)data, len);
        timeout[0] = CLIENTTIMEOUT;
    } else
    if (client == clients[1]) {
        Serial.print("Data from client 1 ");
        Serial.write((uint8_t*)data, len);
        timeout[1] = CLIENTTIMEOUT;
    }
}

void onConnect(void* arg, AsyncClient* client) {
    Serial.print("Client has been connected");
}

//Setup functions
void setup_serial_port() {
  //uint32_t baudrate = 115200;
  uint32_t baudrate = 9600;
  Serial.begin(baudrate);
  Serial.println("");
  Serial.print("Serial port connected: ");
  Serial.println(baudrate);
}

void setup_wifi() {
  uint8_t wait = 0;
  while (WiFi.status() != WL_CONNECTED) {
    if (wait) {
      --wait;
    } else {
      wait = 40;
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, pass);
    }
    delay(100);
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void setupClients() {
    uint8_t i;
    for (i = 0; i < NUM_CLIENTS; ++i) {
        clients[i] = new AsyncClient();
        clients[i]->onData(&handleData, clients[i]);
        clients[i]->onConnect(&onConnect, clients[i]);   
    }
}