• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

жизненный цикл TCP подключения в espconn

_hg_

New member
Друзья, кто-нибудь (я уверен здесь такие есть) может объяснить, как работает ESP8266 с espconn при подключении в качестве клиента: ESP8266 (client) - TCP connection ---> SERVER (e.g. google.com) ?

То есть я хочу узнать как оно работает с данными изнутри. Почему часто из черного ящика espconn доносится "already freed" и всякие LoadProhibitedCause ?

Вот например существует функция

Код:
int work_controller (struct controller_data *ctl_data, uint32_t command)
{
    // К этому освобождению ранее выделенной структуры пришёл методом научного втыка
    // Если это не сделать, а взять и переинициализировать структуру, выделенную ранее (переданную сюда в качестве аргумента), то происходят крики изнутри соединения (аномалии всякие LoadProhibited и т.д.)
    // ВОТ В ЭТОМ И ХОЧУ РАЗОБРАТЬСЯ. ЧТО ПРОИСХОДИТ ВНУТРИ.
    // ПОЧЕМУ НЕЛЬЗЯ ПЕРЕИСПОЛЬЗОВАТЬ ОДНУ СТРУКТУРУ ?
    if (ctl_data) {
        free(ctl_data);
        ctl_data = NULL;
    }

//---------------------- cut ------------------------// отсюдя начиналась функция до научного втыка.

    if (!ctl_data) {
        ctl_data = (struct controller_data *)zalloc(sizeof(struct controller_data) + SEND_BUFFER_MAX);
        if (!ctl_data) {
            return -1;
        }
        ctl_data->data = (uint8_t *)(ctl_data + 1);
    }
    else {
        // переиспользуем ранее выделенный буфер:
        // тут я заполняю структуру и обнуляю буфер данных
        // ВНИМАНИЕ: если эту переинициализированную структуру использовать,
        // то происходит LoadProhibited где-то в попытке соединения с удаленным сервером.
        // До использования этой структуры моим кодом дело не доходит. Моя ошибка исключена.
        memset(((uint8_t *)ctl_data->data + sizeof(struct controller_data)), 0x00, SEND_BUFFER_MAX);
    }

    if (command == CONTROLLER_API_STOP) {
        if (ctl_data) free(ctl_data);
        return 0;
    }

    ctl_data->command = command;

    switch (ctl_data->command) {

    case CONTROLLER_API_SAVE_METRIC:

        if (!controller_save_metric(ctl_data)) {
            free(ctl_data);
            return -1;
        }
        break;

    case CONTROLLER_API_ADD_DEVICE:
    
        if (!controller_add_device(ctl_data)) {
            free(ctl_data);
            return -1;
        }
        break;

    default:
        free(ctl_data);
        return -1;
    }

    // эта строка для отладки и исключения ошибок в динамической передаче IP
    struct ipaddr controller_ip; ((uint32_t *)&controller_ip)[0] = (100 << 24 | 0 << 16 | 168 << 8 | 192);

    struct tcp_handlers h;
    memset(&h, 0, sizeof(struct tcp_handlers));

    h.tcp_connected        = work_connected;
    h.tcp_write_finish    = work_write_finish;
    h.tcp_received        = work_received;
    h.tcp_sent            = work_sent;
    h.tcp_reconnected    = work_reconnected;
    h.tcp_disconnected    = work_disconnected;

    // create_tcp_connection: выделяет espconn, заполняет IP, PORT, espconn->reverse = ctl_data, калбэки и таймаут.
    // а затем создает подключение. и следующая стадия - work_connected, который отправляет первую порцию данных.
    // а в work_disconnected мы меняем команду на следующую (CONTROLLER_API_ADD_DEVICE) и снова вызываем эту функцию для совершения следующего (если ещё не CONTROLLER_API_STOP) подключения.
    if (create_tcp_connection(&controller_ip, 80, &h, (void *)ctl_data, 30)) {
        free(ctl_data);
        return -1;
    }
    return 0;
}
Вот вопрос: ЧТО ПРОИСХОДИТ ВНУТРИ ? Почему нельзя ПЕРЕИСПОЛЬЗОВАТЬ ОДНУ СТРУКТУРУ ?
Не могу найти описания жизненного цикла этих espconn. Их не существует или мне нужно повысить уровень гугления ?
 
Последнее редактирование:

pvvx

Активный участник сообщества
Их не существует или мне нужно повысить уровень гугления ?
"Их не существует", "повысить уровень гугления" до:
[inline]err_t tcp_write(struct tcp_pcb * pcb, void * dataptr, u16_t len, u8_t apiflags)[/inline]
рассмотреть значения и почему существует apiflags.

Так-же "повысить уровень гугления" до: как распределяется HEAP. При образовании новой структуры psb, Lwip выделяет в памяти место под неё и возвращает вам ID, который является адресом-указателем на эту структуру. При закрытии соединения, LwIP освобождает эту память. Далее, к примеру, инициализирует другую pcb для другого соединения. При запросе у менеджера Heap места под новую структуру он, с вероятностью в 90%, получит тот –же адрес, следовательно такую-же ID pcb. Если вы не перехватываете все калбаки от LwIP, то ваши процедуры далее будут работать с чужой pcb :)

Espconn по тому никем и не пользуется, что там куча ошибок…
Единственная цель espconn – избавить пользователя SDK от сопряжения с LwIP TLS/SSL соединений. Но, т.к. на сегодня ESP8266 не в состоянии обеспечивать современный уровень TLS/SSL соединений с любым общественным сервером в инет, то espconn является никчемной примочкой, пожирающей память и вносящей ошибки в ПО.
 
Последнее редактирование:
  • Like
Реакции: _hg_
Сверху Снизу