Для распознавания отключения TCP ESP32 требуется очень много времени

Я использую следующий класс для создания потока из подключения Wi-Fi (сервера). Клиент (приложение для ПК) подключается к ESP32, а затем выдает команды по этому соединению. Это прекрасно работает. Когда клиент изящно отключается, соединение сбрасывается, и ESP32 готов к другому подключению. Только один клиент может подключаться одновременно, но пока это нормально.

Проблема возникает, когда клиент неожиданно отключается (например, если я просто убью процесс на ПК). Соединение остается открытым в течение очень долгого времени (около 10 минут), пока ESP32 не обнаружит, что соединение прервалось. В течение этого времени никакое новое соединение не может быть установлено. В этом состоянии я все еще вижу, как он печатает "Все еще подключенные" сообщения на последовательную консоль с уменьшением скорости (количество сообщений в секунду значительно снижается, пока он, наконец, не сдастся).

Есть ли способ уменьшить время ожидания при отключенном соединении? Само (рабочее) соединение также может долго простаивать, поэтому то, что сообщения не принимаются, не означает, что мы можем прервать соединение с конца ESP32.

Функция Connect() ниже вызывается из loop (), и в обычном режиме она просто выводит сообщения "Новый клиент подключен" и "клиент отключен".


class WifiCachingStream : public Stream
{
private:
    WiFiServer _server;
    WiFiClient _activeClient;
    bool _hasActiveClient;
public:
    WifiCachingStream(int port) :
    _server(port), _activeClient()
    {
        _hasActiveClient = false;
    }

    void Init()
    {
        _server.begin();
    }

    bool Connect();

    int read() override;

    size_t write(byte b) override;

    void maintain();

    int available() override
    {
        return _activeClient.available();
    }

    int peek() override
    {
        return _activeClient.peek();
    }

    void flush() override
    {
        // Ничего не делай. Реализация WiFiClient очищает очередь _INPUT_ вместо очереди вывода!
        // _activeClient.flush();
    }

    bool isConnected() const
    {
        return _hasActiveClient;
    }
};

int idx = 0; // только для тестирования
bool WifiCachingStream::Connect()
{
    if (_activeClient.available() || _activeClient.connected())
    {
        if ((idx ++) % 10000 == 0)
        {
            // Для тестирования: Это выводится на консоль даже после того, как связь на ПК была прервана
            Serial.println("Все еще подключен");
            // Это (попытка) отправить сообщение по ссылке, которое, как я ожидаю, приведет к тому, что реализация обнаружит, что соединение было прервано.
            Firmata.sendString(F("Все еще подключен"));
        }
        return true;
    }

    _activeClient.stop();
    _activeClient = _server.accept();

    if (_activeClient)
    {
        Serial.println("Новый подключенный клиент");
        WiFi.setSleep(false);
        _hasActiveClient = true;
        return true;
    }

    if (_hasActiveClient)
    {
        _hasActiveClient = false;
        SSerial.println("Клиент отключен - вход в режим низкого энергопотребления Wi-Fi");
        // Режим низкого энергопотребления значительно увеличивает время в оба конца, но когда никто
        // не подключен, это нормально.
        WiFi.setSleep(true);
    }
    
    return false;
}

// Other functions irrelevant

, 👍1


1 ответ


Лучший ответ:

1

Это более или менее жизненный факт, что обнаружение TCP потерянного соединения (нелюбезное отключение) занимает много времени, когда по нему ничего не передается.

Причин может быть несколько странных и любопытных keepalive и параметры времени ожидания для самого протокола, но внедрение сердцебиение (назовем его уровня приложения удержание), отправленный клиентом, и связь с ESP32-концу, когда сердце не бьется/сообщение не было получено в течение определенного периода, вероятно, ваш лучший выбор, и это даст вам точный контроль над тайм-аутом.

,

Я подумаю об этом, но на самом деле я не контролирую протокол. Добавление сообщения о сердцебиении обсуждалось, но еще не утверждено. Мне нужно проверить эту нить., @PMF