Продолжаем работу с протоколом TCP (Transmission Control Protocol). И на данном уроке мы уже попробуем не просто соединиться с сервером и передать тестовый пакет, но и также, передавая пакеты, мы попробуем такие пакеты ещё и принять. Мы также этим раньше занимались с использованием других контроллеров, поэтому нам будет гораздо легче справиться с нашей задачей.
Схема наша осталась прежняя
Проект мы, за основу возьмём из прошлого урока с именем WIFI_STA_TCP_CLIENT_CONNECT и дадим ему новое имя WIFI_STA_TCP_CLIENT.
Откроем наш проект в Espressif IDE и в файле tcp.c сначала объявим глобальную структуру для передачи параметров в задачу приёма пакета, а также объявим переменную типа данной структуры
После функции vLCDTask добавим функцию задачи приёма пакетов с сервера, в теле которой объявим указатель на тип только что созданной нами переменной типа структуры, переменную типа структуры передачи параметров в задачу вывода информации на дисплей, а также объявим очередь
Присвоим указатель на параметры задачи нашему указателю
Объявим небольшой символьный буфер, также целочисленную переменную и флаг, смысл которого мы поймём чуть позже
Присвоим позицию, взятую из параметра, аналогичному полю очереди, а также указатель на наш буфер соответствующему указателю очереди дисплея
Объявим переменную с количеством милисекунд, которые будет ждать наш клиент при попытке принять пакет от сервера и, используя соответствующую функцию, применим данный таймаут к нашему сокету
Добавим бесконечный цикл, в котором попытаемся принять пакет
Здесь мы будем висеть до тех пор, пока не примем пакет либо пока не истекут 1000 милисекунд в соответствии с нашими настройками сокета.
Данная функция возвращает количество принятых байтов в пакете или -1 в случае ошибки.
Для интереса отправим в терминал значение данного параметра
В случае ошибки приёма выведем в терминальную программу соответствующее сообщение
Добавим глобальную очередь для передачи флага состояния из другой задачи
xQueueHandle lcd_string_queue = NULL, xQueueClose = NULL;
Поработаем пока с задачей создания сокета и передачи пакетов, для чего в её функции tcp_task объявим чистый (ни куда не указывающий) указатель на задачу приёма пакета
TaskHandle_t xLCDTaskHandle = NULL, xRecvTaskHandle = NULL;
Ниже создадим задачу, проинициализировав сначала параметры
Подождём 2 секунды
С интервалом в 2 секунды передадим пакет серверу
Выйдем из цикла и из условия и удалим вот эти старые строки
vTaskDelay( 2000 / portTICK_RATE_MS);
sprintf(str1, "Hello from ESP!!!\n");
write(sockfd,(void *) str1,strlen(str1));
vTaskDelay( 2000 / portTICK_RATE_MS);
Объявим флаг, проинициализируем его единицей и отправим его с помощью очереди в нашу задачу приёма пакета
Вот теперь нам будет ясен смысл нашего флага. Передача с помощью него единицы даст команду на уничтожение задачи приёма пакетов перед закрытием сокета и разрывом соединения с сервером.
Добавим ещё одну глобальную очередь для передачи флага уничтожения задачи обратно из задачи приёма пакетов, чтобы отследить момент, когда задача будет уже уничтожена
xQueueHandle lcd_string_queue = NULL, xQueueClose = NULL, xQueueCloseAsk = NULL;
Вернёмся в функцию tcp_task и добавим бесконечный цикл, в котором, собственно и будем отслеживать данный флаг, и попытаемся получить его из очереди
Если вернулась единица, то отправим соответствующее уведомление в терминальную программу и выйдем из цикла
А если мы не попали в данное условие, то добавим небольшую задержку
Ниже удалим функцию отключения сокета, так как она перед его закрытием не имеет смысла
vTaskDelay( 10 / portTICK_RATE_MS);
}
shutdown(sockfd, 0);
Я читал, что данная функция имеет тот же смысл, что и функция закрытия сокета, отличается лишь тем, что сразу не уничтожает буфер, чтобы дать до конца принять пакет.
Создадим наши обе очереди
Чуть ниже удалим уничтожение очереди и задачи дисплея
vTaskDelete(xLCDTaskHandle);
vQueueDelete(lcd_string_queue);
В функции приёма пакетов recv_task в самом начале бесконечного цикла узнаем, не пришла ли команда на уничтожение задачи. Если пришла, то отправим флаг в другую очередь и уничтожим задачу
В принципе, мы можем теперь проверить соединение с сервером, отправку пакетов и разрыв соединения после передачи десяти пакетов.
Запустим сначала wireshark и отфильтруемся по сетевому адресу нашего модуля (как это делать, мы давно знаем), затем в netcat дадим команду на прослушку порта и перезагрузим наш модуль, соответственно перед этим не забыв его прошить.
Сначала мы увидим на дисплее сообщение о соединении с сервером
Посмотрим, как приходят пакеты
В терминале мы увидим вот такое сообщение, которого пугаться не надо, так как клиент просто не дождался пакета от сервера, а мы его и не посылали
По окончанию приёма пакетов сервером мы на дисплее увидим соответствующее сообщение о разрыве соединения
Посмотрим, как отобразился процесс в анализаторе трафика
Всё прекрасно соединяется, передаётся и разъединяется.
Осталось нам лишь научить наш клиент принимать пакеты.
В этой же функции добавим ветку else в условие валидности принятого пакета, в теле которой мы соберём в массив из пакета все символы и отправим его на дисплей
Соберём код, прошьём контроллер, отправив перед этим команду в netcat, и во время передачи пакетов из командной строки попытаемся что-то передать клиенту
Убедимся, что наш клиент принял пакет, увидев такой же текст на дисплее
В момент разрыва соединения с сервером мы также увидим на дисплее соответствующую надпись
Таким образом, в данном уроке нам удалось немного расширить функционал нашего клиента, научив его также принимать пакеты от сервера в независимом потоке.
Всем спасибо за внимание!
Оригинал статьи находится здесь.
<<Предыдущий урок | Следующий урок>>
Недорогие отладочные платы ESP32 можно купить здесь
Недорогие отладочные платы ESP32/ESP32-C3/ESP32-S3 можно купить здесь
Логический анализатор 16 каналов можно приобрести здесь: Дисплей LCD 20x4 можно приобрести тут
Дисплей LCD 16x2 можно приобрести тут
Переходник I2C to LCD1602 2004 можно приобрести здесь
Многофункциональный переходник CJMCU FT232H USB к JTAG UART FIFO SPI I2C можно купить здесь
Видео в Rutube
Видео в Дзен
Видео в Youtube