Продолжаем работу с протоколами модели OSI и на данном уроке мы попытаемся создать простой сервер HTTP, который позволит нам принять запрос документа от клиента, обработать его и в ответ направить клиенту нужную информацию. Также мы раньше подобные задачи решали с использованием других контроллеров, в том числе и родственного ESP8266, поэтому думаю, что с данной задачей мы без особого труда справимся. Сервер считается простым, так как отвечать он будет на запросы не любых документов, а только главной страницы и иконки приложения. Также мы для упрощения задачи не используем шифрование.
Дисплей нам на данном уроке не потребуется, поэтому схема наша будет состоять только из отладочной платы с контроллером ESP32, подключенной к USB-порту компьютера
Проект за основу мы возьмём из прошлого урока с именем WIFI_STA_TCP_SERVER и присвоим ему имя WIFI_STA_HTTP_SERVER.
Откроем проект в Espressif IDE и удалим файлы lcd2004.h, lcd2004.c, i2c_user.h и i2c_user.c, так как с дисплеем мы работать не будем. Также подключение данных модулей мы удалим и в файле CMakeLists.txt
set(COMPONENT_SRCS "main.c wifi.c tcp.c i2c_user.c lcd2004.c")
В файле Kconfig.projbuild удалим секции, отвечающие за ножки I2C
config SDA_GPIO int "SDA GPIO number" range 0 48 default 21 help GPIO number SDA.
config SCL_GPIO int "SCL GPIO number" range 0 48 default 22 help GPIO number SCL.
Зайдём в конфигуратор и изменим порт на значение по умолчанию для работы с протоколом HTTP
Удалим подключение заголовочного файла из main.h и tcp.h
#include "lcd2004.h"
В функции app_main файла main.c удалим строки связанные с инициализацией дисплея
ret = i2c_ini();ESP_LOGI(TAG, "i2c_ini: %d", ret);LCD_ini();
Файлы tcp.h и tcp.c переименуем соответственно в http.h и http.c.
Изменим подключение модуля также в файле CMakeLists.txt
set(COMPONENT_SRCS "main.c wifi.c http.c")
Перейдём в файл http.c и удалим функцию vLCDTask вместе с телом.
Удалим также и функцию client_socket_task.
Структуры и очереди нам также не потребуются
typedef struct struct_client_socket_t { struct sockaddr_in cliaddr; socklen_t sockaddrsize; int accept_sock; uint16_t y_pos;} struct_client_socket;struct_client_socket client_socket01;//-------------------------------------------------------------typedef struct{ unsigned char y_pos; unsigned char x_pos; char *str;} qLCDData;//------------------------------------------------xQueueHandle lcd_string_queue = NULL, xQueueClose = NULL, xQueueCloseAsk = NULL;
Переименуем строку
static const char *TAG = "http";
Также переименуем функцию задачи
void http_task(void *pvParameters)
Не забываем также о прототипе в заголовочном файле. Также в функции app_main файла main.c переименуем аргументы в создании задачи
xTaskCreate(http_task, «http_task«, 4096, NULL, 5, NULL);
Вернёмся в файл http.c и в функции http_task удалим объявление хендла задачи дисплея
TaskHandle_t xLCDTaskHandle = NULL;
Удалим инициализацию позиции
unsigned char y_pos = 0;
Удалим также вот эти строки
qLCDData xLCDData;char str1[21];xLCDData.y_pos = 1;xLCDData.str = str1;
Удалим и вот эти строки, также связанные с дисплеем
lcd_string_queue = xQueueCreate(10, sizeof(qLCDData));xQueueClose = xQueueCreate(10, sizeof(unsigned char));xQueueCloseAsk = xQueueCreate(10, sizeof(unsigned char));xTaskCreate(vLCDTask, «vLCDTask», 2048, NULL, 2, &xLCDTaskHandle);
Здесь удалим перевод строки, чтобы не создавалась лишняя, в функции для вывода логов строки переводятся автоматически
ESP_LOGI(TAG, «Create socket…\n«);
…
ESP_LOGE(TAG, «socket not created\n«);
Тут исправим грамматическую ошибочку
//Свяжем сокет с адресом сервера
В следующем условии удалим уничтожение задачи и очереди
vQueueDelete(lcd_string_queue);vTaskDelete(NULL);
Тело следующего условия удалим полностью
if(accept_sock >= 0)
{ client_socket01.accept_sock = accept_sock; client_socket01.cliaddr = cliaddr; client_socket01.sockaddrsize = sockaddrsize; client_socket01.y_pos = y_pos%4; xTaskCreate(client_socket_task, "client_socket_task", 4096, (void*)&client_socket01, 5, NULL); y_pos++;
}
В конце тела функции удалим вот эти строки
sprintf(str1, "Disonnected");xQueueSendToBack(lcd_string_queue, &xLCDData, 0);vTaskDelay(2000 / portTICK_RATE_MS);vTaskDelete(xLCDTaskHandle);vQueueDelete(lcd_string_queue);
Теперь у нас хотя бы будет собираться код.
Добавим переменную в объявление
int sockfd, accept_sock, ret;
Объявим указатель на буфер, а также объявим и инициализируем длину буфера
В условии, тело которого мы удалили, запросим память для буфера и попытаемся принять от клиента пакет
Теперь нам надо будет подготовить документы, которые мы будем предоставлять клиенту на его запросы.
Сделаем мы это так, как делали раньше с AVR, подготовив массив с помощью утилиты makefsdata (в конце страницы будет ссылка на архив утилиты с примерами страницы и иконки). Содержимое страницы и заголовка HTTP мы поместим в глобальные массивы
С иконкой поступим немного по-другому. Мы её не будем собирать из двух массивов, а создадим для неё общий массив вместе с заголовком. Памяти лишней мы не истратим, так как иконка у нас одна. Зато передавать мы её будем сразу из исходного массива
Вернёмся в функцию http_task и поместим наш ответ на запрос главной страницы в буфер, соединив наши массивы заголовка и контента страницы, а перед этим отфильтровав всё ненужное
Отправим пакет клиенту
А если запрос был на иконку, то передадим наш массив сразу, ничего не копируя и не соединяя
Выйдем из условия наличия ненулевого пакета (посчитайте закрывающие скобки) и разъединимся с клиентом, а затем освободим память, данную нам под буфер
В принципе, это весь код нашего простенького сервера HTTP. Соберём проект, прошьём контроллер и в терминале запомним сетевой адрес нашего сервера (отладочной платы)
Попытаемся в браузере запросить страницу и, если всё нормально, то мы получим и страницу и иконку
В анализаторе трафика у нас тоже всё нормально. Все ответы пришли, порты после получения документов отключились
Итак, на данном уроке нам удалось создать простейший HTTP-сервер, который может обрабатывать запрос документов от клиента и передавать ему их в форме пакета HTTP.
Всем спасибо за внимание!
Оригинал статьи находится здесь.
<<Предыдущий урок | Следующий урок>>
Утилита для получения двоичного кода страниц и других файлов: makefsdata
Недорогие отладочные платы ESP32 можно купить здесь
Недорогие отладочные платы ESP32/ESP32-C3/ESP32-S3 можно купить здесь
Логический анализатор 16 каналов можно приобрести здесь
Многофункциональный переходник CJMCU FT232H USB к JTAG UART FIFO SPI I2C можно купить здесь
Видео в Rutube
Видео в Дзен
Видео в Youtube