Продолжаем работу с беспроводной сетью в режиме станции (STA) контроллера ESP32. И на данном уроке мы уже начнём работать с протоколом TCP (Transmission Control Protocol). Хотя, мы уже давно с данным протоколом работаем, изучили, можно сказать, его вдоль и поперёк. Мы знаем, что по сравнению с протоколом UDP данный протокол обладает рядом преимуществ — это его надёжность передачи данных, которая обеспечивается тем, что на каждый определённый участок данных требуется подтверждение от принимающей стороны, тем самым обеспечивается гарантированная доставка данных получателю, а также сохранение порядка следования сообщений. Конечно, надёжность эта достаётся не совсем дешевой ценой — нужно корректно создавать соединение с узлом, также корректно разъединяться, обеспечить подтверждение пакетов, следить за порядком следования сегментов и т.д. Но всё это нас не пугает, мы это изучили давным-давно, тем более, что часть данных забот возьмёт на свои плечи библиотека LWIP и её интерфейс SOCKET.
Схема наша также не изменилась и осталась такая же, как и в прошлом уроке
Так как протокол TCP не очень лёгкий, то работу с ним мы также разобьём на несколько уроков и в данном уроке мы создадим простой клиент, который пока только попытается создать соединение с сервером и затем его разорвать.
Проект был выполнен из проекта также прошлого урока с именем WIFI_STA_UDP_SERVER и получил новое имя WIFI_STA_TCP_CLIENT_CONNECT.
Откроем наш проект в Espressif IDE и переименуем файлы udp.h и udp.c соответственно в tcp.h и tcp.c, согласившись с переформированием ссылок на файлы
В файле CMakeLists.txt изменения вносим вручную
set(COMPONENT_SRCS "main.c wifi.c tcp.c i2c_user.c lcd2004.c")
В файле tcp.c функцию udp_task мы для порядка переименуем в tcp_task, не забывая также о её прототипе в заголовочном файле.
В функции app_main файла main.c также внесём соответствующее изменение в создании задачи
xTaskCreate(tcp_task, "tcp_task", 4096, NULL, 5, NULL);
Вернёмся в файл tcp.c и также для порядка изменим строку вывода в лог
static const char *TAG = "tcp";
В функции удалим объявление следующей строки
char buf[10] = {};
А в этом символьном массиве увеличим количество элементов
char str1[21];
Изменим тип протокола в строке создания сокета
if ( (sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0 ) {
Следующий цикл удалим, но тело его оставим
xTaskCreate(vLCDTask, «vLCDTask», 2048, NULL, 2, &xLCDTaskHandle);
while(1)
{
…….
}
Поэтому здесь удалим break
ESP_LOGE(TAG, «socket not created\n»);
break;
Вместо этого будет будет удаление задач и очереди
1 2 3 4 |
ESP_LOGE(TAG, "socket not created\n"); vTaskDelete(xLCDTaskHandle); vQueueDelete(lcd_string_queue); vTaskDelete(NULL); |
Вот эту строку с вычислением размера структуры также удалим
uint32_t client_addr_len = sizeof(cliaddr);
Заполним информацию о клиенте и свяжем сокет с адресом клиента
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
servaddr.sin_port = htons(CONFIG_SERVER_PORT); //Заполнение информации о клиенте cliaddr.sin_family = AF_INET; // IPv4 cliaddr.sin_addr.s_addr = INADDR_ANY; cliaddr.sin_port = htons(CONFIG_CLIENT_PORT); //Свяжем сокет с адресом клиента if (bind(sockfd, (const struct sockaddr *)&cliaddr, sizeof(struct sockaddr_in)) < 0 ) { ESP_LOGE(TAG, "socket not binded\n"); vTaskDelete(xLCDTaskHandle); vQueueDelete(lcd_string_queue); vTaskDelete(NULL); } ESP_LOGI(TAG, "socket was binded\n"); |
В следующей строке исправим инициализацию поля
servaddr.sin_addr.s_addr = inet_addr(CONFIG_SERVER_IP);
Чтобы не запутаться, после следующей строки удалим весь оставшийся код тела функции
servaddr.sin_port = htons(CONFIG_SERVER_PORT);
Попытаемся соединиться с сервером, если соединение прошло удачно, то выведем соответствующее сообщение на дисплей, затем подождём 2 секунды и попытаемся передать строку серверу, после чего подождём ещё 2 секунды
1 2 3 4 5 6 7 8 9 10 |
servaddr.sin_port = htons(CONFIG_SERVER_PORT); if (connect(sockfd, (struct sockaddr *)&servaddr,sizeof(struct sockaddr_in)) >= 0) { sprintf(str1, "Connected"); xQueueSendToBack(lcd_string_queue, &xLCDData, 0); vTaskDelay( 2000 / portTICK_RATE_MS); sprintf(str1, "Hello from ESP!!!\n"); write(sockfd,(void *) str1,strlen(str1)); vTaskDelay( 2000 / portTICK_RATE_MS); } |
После попытки разрыва соединения выведем соответствующее сообщение на дисплей, а затем, подождав также пару секунд удалим задачи и очередь
1 2 3 4 5 6 7 8 9 10 |
vTaskDelay( 2000 / portTICK_RATE_MS); } shutdown(sockfd, 0); close(sockfd); sprintf(str1, "Disonnected"); xQueueSendToBack(lcd_string_queue, &xLCDData, 0); vTaskDelay( 2000 / portTICK_RATE_MS); vTaskDelete(xLCDTaskHandle); vQueueDelete(lcd_string_queue); vTaskDelete(NULL); |
Последние 2 секунды мы ждём для того, чтобы сообщение успело вывестись на дисплей до уничтожения задачи дисплея и очереди.
Вот и готов наш проект.
Но прежде чем его испытать, нам нужно сконфигурировать адрес и порт сервера, с которым мы будем пытаться соединяться.
Как узнать IP компьютера в сети, мы все знаем, поэтому узнаем его и данный адрес впишем и в конфигураторе, также впишем номера портов сервера и клиента
Соберём и прошьём нашу программу и узнаем сетевой адрес платы в терминале
Так как пока сервер не слушает порт, то мы получим соответствующее сообщение на нашем дисплее
Для начала на компьютере откроем Wireshark и настроим его на приём трафика только с адреса нашей платы
Затем запустим netcat и начнём слушать порт, назначенный нами в конфигураторе
Перезагрузим контроллер и, если всё правильно, то на дисплее мы сначала увидим следующее сообщение
Затем через 2 секунды в программе netcat мы увидим присланное сообщение
И ещё через 2 секунды на дисплее появится сообщение, сигнализирующее о разрыве соединения
Также весь процесс обмена мы можем наблюдать в Wireshark
Мы видим здесь, что соединение происходит корректно — путём трёхкратного рукопожатия, также обоюдно происходит и его разрыв.
Итак, на данном уроке нам удалось создать простейший TCP-клиент, который способен соединиться и разъединиться с сервером, а также передали на сервер пакет данных.
Всем спасибо за внимание!
Предыдущий урок Программирование МК ESP32 Следующий урок
Недорогие отладочные платы ESP32 можно купить здесь Недорогие отладочные платы ESP32
Недорогие отладочные платы ESP32/ESP32-C3/ESP32-S3 можно купить здесь Недорогие отладочные платы ESP32
Логический анализатор 16 каналов можно приобрести здесь
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в Дзен (нажмите на картинку)
Добавить комментарий