TCP server freezes totally the P2/Argon module after client (not proper) disconnection

Hi,

We use the P2 as a TCP server. When a client connects it to the server of P2 and we disconnect it with a not proper way, with eg. disable the wifi of the client, the P2 freeze.

Client eg. windows telnet:
telnet IP_OF_p2 3456

(after connection leave it for a few sec to run, then disable the wifi of your PC or laptop)

Firmware on Argon és P2 verzió: 5.1.0
Tested on Argon as well, the same problem.

P2 code:

#include "Particle.h"
#include "application.h"

SYSTEM_THREAD(ENABLED);
//STARTUP(System.enableFeature(FEATURE_DISABLE_LISTENING_MODE));
STARTUP(WiFi.selectAntenna(ANT_INTERNAL));
SYSTEM_MODE(AUTOMATIC);

TCPServer server = TCPServer(3456);
TCPClient client;
boolean tablet_client_connected = false;
unsigned long client_connected_counter = 0;
unsigned long free_memory_error_millis = 0;
unsigned long last_send_tablet_data = 0;
unsigned long last_loop_wifi = 0;
byte tcp_msg[1152] = {0};
unsigned long last_blink = 0;
unsigned long blink_interval = 100;
bool blink_state = false;
int led = D7;

void setup() {
    Serial.begin(115200);

    WiFi.on();
    WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
    
    server.begin();
}

void loop() {
    if (millis() - last_blink > blink_interval) {
        last_blink = millis();
        blink_state = !blink_state;
        digitalWrite(led, blink_state);
        Serial.printlnf("Cycle\t%lu", System.freeMemory());
    }
/*
    if (client.connected()) {
        if (free_memory_error_millis > 0 && millis() - free_memory_error_millis > 3000) {
            Serial.println("ipad disconnection detected");
            client.flush();
            client.stop();
            client.flush();
            client.stop();
            free_memory_error_millis = 0;
        }
    }
*/
    send_tcp_msg();

    if (client.connected()) {
        tablet_client_connected = true;

        auto randomclient = server.available();
        if(randomclient.connected()) {
            randomclient.stop();
        }

        loop_wifi();
    }
    else {
        if (tablet_client_connected == true) {
            tablet_client_connected = false;
            Serial.print(millis());
            Serial.println(" disconnected ipad");
            client.stop();
        }

        client = server.available();
        if (client.connected()) {
            tablet_client_connected = true;
            Serial.print(millis());
            Serial.println(" connected ipad");
            client_connected_counter++;
        }
    }
}

void loop_wifi() {
    if(millis() - last_loop_wifi >= 100) {
        Serial.printlnf("a");
        last_loop_wifi = millis();

        if (client.connected()) {
            Serial.printlnf("b");
            if (client.available()) {
                Serial.printlnf("c");
                byte temp_buf[TCPCLIENT_BUF_MAX_SIZE] = {0};
                int available_bytes = client.available();
                Serial.printlnf("d");
    
                if(available_bytes <= 0)
                    return;
    
                while((available_bytes = client.available()) > 0) {
                    if(available_bytes > 0) {
                        client.read(temp_buf, available_bytes);
                    }
                }
                Serial.printlnf("e");
            }
        }
    }
}

void send_tcp_msg() {
    if(millis() - last_send_tablet_data >= 100) {
        Serial.printlnf("1");
        last_send_tablet_data = millis();

        if(client.connected()) {
            Serial.printlnf("2");
            memset(tcp_msg, 'A', sizeof(tcp_msg));
            Serial.printlnf("2-0");
            client.write(tcp_msg, 1152, 0);
            Serial.printlnf("2-1");
            client.flush();
            Serial.printlnf("2-2");
            int tcpWriteErr = client.getWriteError();
            /*if(tcpWriteErr < 0) {
                Serial.print("tablet2: ");
                Serial.println(tcpWriteErr);
            }*/

            if (tcpWriteErr != 0) {
                client.flush();

                if(free_memory_error_millis == 0) {
                    free_memory_error_millis = millis();
                }
            }
            else {
                free_memory_error_millis = 0;
            }
        }
        Serial.printlnf("3");
    }
}

Can you please help us to solve this problem?

Thanks!

Don’t use client.available(). Instead call client.read() and check the result code.

If the result is > 0 then that many bytes were read. If the result == 0, then there is no data available.

If the result is < 0, then a connection error occurred.

The problem is that available() doesn’t actually return a negative result code if the socket closed, so there’s no way to tell if the connection is closed or no data has arrived, so just going directly to read() is the better option.

1 Like

Hello Rickkas,

Thanks, but the problem is with the write.

Freezes at 2-0

Now I have made a simpler code without any read.

#include "Particle.h"
#include "application.h"

SYSTEM_THREAD(ENABLED);
//STARTUP(System.enableFeature(FEATURE_DISABLE_LISTENING_MODE));
STARTUP(WiFi.selectAntenna(ANT_INTERNAL));
SYSTEM_MODE(AUTOMATIC);

TCPServer server = TCPServer(3456);
TCPClient client;
boolean tablet_client_connected = false;
unsigned long client_connected_counter = 0;
unsigned long last_send_tablet_data = 0;
unsigned long last_loop_wifi = 0;
byte tcp_msg[1152] = {0};
unsigned long last_blink = 0;
unsigned long blink_interval = 100;
bool blink_state = false;
int led = D7;

void setup() {
    Serial.begin(115200);

    WiFi.on();
    WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
    
    server.begin();
}

void loop() {
    if (millis() - last_blink > blink_interval) {
        last_blink = millis();
        blink_state = !blink_state;
        digitalWrite(led, blink_state);
        Serial.printlnf("Cycle\t%lu", System.freeMemory());
    }

    send_tcp_msg();

    if (client.connected()) {
        tablet_client_connected = true;

        auto randomclient = server.available();
        if(randomclient.connected()) {
            randomclient.stop();
        }
    }
    else {
        if (tablet_client_connected == true) {
            tablet_client_connected = false;
            Serial.print(millis());
            Serial.println(" disconnected ipad");
            client.stop();
        }

        client = server.available();
        if (client.connected()) {
            tablet_client_connected = true;
            Serial.print(millis());
            Serial.println(" connected ipad");
            client_connected_counter++;
        }
    }
}

void send_tcp_msg() {
    if(millis() - last_send_tablet_data >= 100) {
        Serial.printlnf("1");
        last_send_tablet_data = millis();

        if(client.connected()) {
            Serial.printlnf("2");
            memset(tcp_msg, 'A', sizeof(tcp_msg));
            Serial.printlnf("2-0");
            client.write(tcp_msg, 1152, 0);
            Serial.printlnf("2-1");
            client.flush();
            Serial.printlnf("2-2");
        }

        Serial.printlnf("3");
    }
}

@atom Unfortunately this is a bug in our TCPClient::write() implementation with handling 0 timeout values which are supposed to make writes non-blocking, but SO_SNDTIMEO option set to 0 actually means ‘no timeout - block until written’.

As a temporary workaround you may set the timeout to 1 (1 millisecond) in your write() calls until this is fixed in a future Device OS release.

2 Likes

@avtolstoy thank you for your reply.
We have tried. At least it does not freeze completely but it still lags the P2 for 1 sec every cycle.

Can you please give us a time estimation? Will it be fixed within days, weeks, months or years?
Any other suggestion maybe to make a workaround?

#include "Particle.h"
#include "application.h"

SYSTEM_THREAD(ENABLED);
//STARTUP(System.enableFeature(FEATURE_DISABLE_LISTENING_MODE));
STARTUP(WiFi.selectAntenna(ANT_INTERNAL));
SYSTEM_MODE(AUTOMATIC);

TCPServer server = TCPServer(3456);
TCPClient client;
boolean tablet_client_connected = false;
unsigned long client_connected_counter = 0;
unsigned long last_send_tablet_data = 0;
unsigned long last_loop_wifi = 0;
byte tcp_msg[1152] = {0};
unsigned long last_blink = 0;
unsigned long blink_interval = 100;
bool blink_state = false;
int led = D7;

void setup() {
    Serial.begin(115200);

    WiFi.on();
    WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
    
    server.begin();
}

void loop() {
    if (millis() - last_blink > blink_interval) {
        last_blink = millis();
        blink_state = !blink_state;
        digitalWrite(led, blink_state);
        Serial.printlnf("Cycle\t%lu", System.freeMemory());
    }

    send_tcp_msg();

    if (client.connected()) {
        tablet_client_connected = true;

        auto randomclient = server.available();
        if(randomclient.connected()) {
            randomclient.stop();
        }
    }
    else {
        if (tablet_client_connected == true) {
            tablet_client_connected = false;
            Serial.print(millis());
            Serial.println(" disconnected ipad");
            client.stop();
        }

        client = server.available();
        if (client.connected()) {
            tablet_client_connected = true;
            Serial.print(millis());
            Serial.println(" connected ipad");
            client_connected_counter++;
        }
    }
}

void send_tcp_msg() {
    if(millis() - last_send_tablet_data >= 100) {
        Serial.printlnf("last_send_tablet_data: %lu %lu", millis(), millis() - last_send_tablet_data);
        //Serial.printlnf("1");
        last_send_tablet_data = millis();

        if(client.connected()) {
            //Serial.printlnf("2");
            memset(tcp_msg, 'A', sizeof(tcp_msg));
            //Serial.printlnf("2-0");
            client.write(tcp_msg, 1152, 1);
            //Serial.printlnf("2-1");
            client.flush();
            //Serial.printlnf("2-2");
        }

        //Serial.printlnf("3");
    }
}