Продолжаем работу с беспроводной сетью в режиме станции (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 можно купить здесь:
На AliExpress Недорогие отладочные платы ESP32
На Яндекс.Маркет Недорогие отладочные платы ESP32
Логический анализатор 16 каналов можно приобрести (AliExpress) здесь
Дисплей LCD 20×4 можно приобрести здесь (AliExpress) Дисплей LCD 20×4
Переходник I2C to LCD можно приобрести здесь (AliExpress) I2C to LCD1602 2004
Дисплей символьный LCD 1602 с впаянным переходником на шину I2C (Яндекс.Маркет)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в Дзен (нажмите на картинку)
Добавить комментарий