Продолжая работу по программированию микроконтроллера ESP8266 с использованием операционной системы реального времени FREEFTOS и, также продолжая тему передачи данных по беспроводной сети посредством протокола UDP, на данном уроке мы попробуем создать простой сервер, который будет слушать постоянно какой-нибудь порт, и если вдруг получит на него пакет с числом, то должен будет ответить отправителю подобным пакетом с числом, составляющим разность числа 32767 с данным числом. То есть это та же задача, которую выполняли приложения, которые мы использовали на смартфоне и ПК.
Схема наша со времён прошлого урока не изменилась
И проект мы за основу также возьмём из прошлого урока с именем WIFI_STA_UDP_CLIENT_RX_RTOS и назовём его WIFI_STA_UDP_SERVER_RTOS.
Откроем наш проект в Eclipse и в файле wifi.c удалим функцию задачи приёма пакетов recv_task вместе с телом, так как принимать пакеты мы теперь будет в основном потоке, как и отвечать на них.
В теле функции основного потока приёма и отправки пакетов udp_task удалим объявление следующей переменной, так как в бесконечном цикле мы не будем пользоваться точной задержкой ибо задержку между пакетами обеспечивает клиент, мы лишь будем принимать их и на них отвечать
portTickType xLastWakeTime;
Объявим небольшой буфер, целочисленную знаковую 16-разрядную переменную, объявим переменную структуры очереди, а также проинициализируем позицию и указатель на строку
1 2 3 4 5 6 |
int sockfd; char buf[10] = {}; short data; qData xLCDData; xLCDData.y_pos = 1; xLCDData.str = str1; |
Далее оставляем инициализацию сокета и инициализацию переменных структур нулями.
А после строки
memset(&cliaddr, 0, sizeof(cliaddr));
предлагаю удалить оставшийся код тела нашей функции, так как изменений будет много и мы можем запутаться.
Узнаем размер структуры для клиента
1 2 |
memset(&cliaddr, 0, sizeof(cliaddr)); int client_addr_len = sizeof(cliaddr); |
Заполним информацию о сервере
1 2 3 4 5 |
int client_addr_len = sizeof(cliaddr); //Заполнение информации о сервере servaddr.sin_family = AF_INET; // IPv4 servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(SERVER_PORT); |
Свяжем наш сокет с адресом нашего сервера
1 2 3 4 5 6 7 8 |
servaddr.sin_port = htons(SERVER_PORT); //Свяжем сокет с адресом сервера if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) < 0 ) { os_printf("socket not binded\n"); vTaskDelete(NULL); } os_printf("socket binded\n", addr_str); |
Далее добавим бесконечный цикл, в котором примем пакет от клиента, заодно узнав информацию о нём и записав её в переменную соответствующей структуры, сформируем строку с числом, являющейся разностью числа 32767 и пришедшего от клиента числа, отправим данное число клиенту в виде пакета UDP, а также отобразим принятое число на нашем дисплее при помощи очереди, ну и после цикла по традиции закроем сокет и удалим задачу
1 2 3 4 5 6 7 8 9 10 11 12 13 |
os_printf("socket binded\n", addr_str); for(;;) { recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &client_addr_len); snprintf(str1, sizeof(str1), "%6d", *(short*)buf); *(short*)buf = 32767 - *(short*)buf; sendto(sockfd, buf, 2, 0, (struct sockaddr*) &cliaddr, sizeof(cliaddr)); xQueueSendToBack(xQueue, &xLCDData, 0); } shutdown(sockfd, 0); close(sockfd); vTaskDelete(NULL); |
Перейдём в файл i2c_user.h и заполним номер порта сервера, например 5555, больше ничего об узлах здесь теперь не важно, клиент может иметь любой адрес и любой порт
#define SERVER_PORT 5555
Соберём код, прошьём контроллер, запустим программу на смартфоне и внесём там настройки нашего сервера, для этого нужно знать кроме порта также IP-адрес нашего ESP8266, который можно посмотреть в терминальной программе при старте программы
Запустим UDP клиент и нажмём Start
Если всё правильно настроили, то клиент начнёт передавать на сервер числа и получать от него также пакеты с числами
На дисплее, который подключен к нашей плате, мы также увидим приходящие с клиента числа
Остановим наш клиент на смартфоне и запустим программу для Windows (ссылка внизу страницы), зайдём там в настройки и также настроим программу на адрес и порт нашего сервера
Нажмём кнопку Start, тем самым запустив клиент
И если всё нормально, пойдёт тот же самый процесс, что и со смартфоном
Я не стал заморачиваться с отображением отправляемых чисел на экране в программе, а отобразил только принятые, так как отправленные мы видим на экране дисплея, подключенного к плате ESP.
Кстати, я пробовал отправку пакетов производить на сервер одновременно с двух клиентов, сервер отлично справляется, единственное только то, что числа на дисплее будут прыгать, но главное, что сервер успешно отвечает двум клиентам.
Таким образом, на данном уроке нам удалось создать нехитрый сервер, работающий по протоколу UDP, который слушает определённый порт, и, приняв пакет, отправляет отправившему клиенту обратный.
Всем спасибо за внимание!
Предыдущий урок Программирование МК ESP8266 Следующий урок
TCP UDP client-server for Android
QR-код на скачивание приложения:
Модуль ESP NodeMCU можно купить здесь: Модуль ESP NodeMCU
Различные модули ЕSP8266 можно приобрести здесь Модули ЕSP8266
Дисплей LCD 20×4 можно приобрести здесь Дисплей LCD 20×4
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Смотреть ВИДЕОУРОК (нажмите на картинку)
Спасибо за Ваши уроки, ждём с нетерпением! Только простите за …. Port через P а не R.
Очень интересные уроки. Не планируете ли вы продолжить их темой вебинтерфейса на базе esp? Это было бы высшей формой практического применения модуля. Пока что всё изложенное в уроках при всей их уникальности и информативности для начинающих годится лишь для самых простых применений далёких от реальных практических задач.