STM Урок 139. LAN8742A. LWIP. SOCKET. HTTP. WebSocket



Продолжим работу с нашим протоколом HTTP, а также с сетью LAN, библиотекой стека протоколов LWIP, её интерфейсом SOCKET, а также с интересующею всех возможностью передачи данных в браузер клиенту, а также обратно от него на сервер без перезагрузки всей страницы. Мы уже на прошлом занятии занимались таким делом и нам, как вы, надеюсь, помните, это удалось. Применяли для этого мы известную технологию AJAX.

Но столкнулись мы с некоторым вопросом при таком способе обмена данными. Для того, чтобы сервер передал какой-то определённый пакет данных, необходимо было, чтобы клиент его обязательно запросил. Также может существовать ситуация, когда серверу нужно передать данные в любой момент. Особенно такая ситуация возникает в таком случае, когда мы, например организуем чат между двумя клиентами. Один клиент хочет передать другому какое-то сообщение. Между клиентами не существует прямого соединения. Они связаны, например, в какой-то соцсети только через сервер, на котором находится сайт соцсети. Поэтому клиент вместе с определённым идентификатором того клиента, которому адресовано данное сообщение, передаёт всё это серверу, а сервер обязан максимально быстро передать сообщение тому клиенту, которому оно адресовано. Но как же быть, ведь по определению технологии AJAX так невозможно, потому что клиент как бы должен его попросить. Поэтому до технологии WebSocket клиент обязан был раз в какое-то время периодично слать на сервер запрос типа: «А нет ли там для меня какого-то сообщения?». Это было не совсем удобно, ни о какой мгновенности обмена сообщениями не было и речи. Поэтому нам на помощь пришла другая технология — WebSocket.

Также и в нашем случае может возникнуть такая ситуация, когда контроллеру нужно будет в браузер клиента передать какой-то пакет информации незамедлительно. Здесь также нам поможет WebSocket.

А ещё, с технологией WebSocket мы уже тоже работали, когда использовали API NETCONN, поэтому, думаю, нам будет гораздо легче, чем если бы мы знакомились с данной технологией с нуля.

Поэтому рассказывать про особенности протокола, который используется в случае применения технологии WebSocket, я не буду, всё это очень неплохо освещено в уроке 129, который вы, надеюсь, уже все посмотрели. Если кто-то не видел данный урок, то непременно посмотрите.

Теперь, когда уже все посмотрели урок 129, мы можем приступить к основной задаче нашего занятия — сделать возможность использования технологии WebSocket с применением уже интерфейса SOCKET библиотеки стека протоколов LWIP.

И поэтому мы теперь смело можем перейти сразу к нашему проекту, который мы сделаем из проекта урока 137 с именем LAN8742_HTTP_SERVER_AJAX_SOCKET, только имя мы, соответственно, присвоим ему новое — LAN8742_WEBSOCKET_SOCKET. Конечно, в имени прослеживается некоторая тавтология, но так уж получилось.

Откроем наш проект в Cube MX и произведём некоторые поправки.

Во-первых включим MBEDTLS

 

 

В Configuration в настройках MBEDTLS, так как там очень много всякого разнообразия, для того, чтобы не включить ничего лишнего отключим сначала всё.

Начнём с самого первого раздела

 

 

Идём в следующий раздел и аналогичные настройки заносим во все пункты, двигаясь плавно сверху вниз по всему списку. А сверху вниз удобнее потому, что когда мы отключаем некоторые пункты сверху, то зависимые от них пункты ниже могут отключаться сами

 

 

Один раздел пропускаем, там уже всё и так отключено. В следующем разделе также всё отключим

 

 

В следующем разделе уже всё отключено.

Сохраним такие настройки и теперь начнём включать нужные опции.

Начнём сразу с раздела Modules. Включим Base64

 

 

Здесь же включим и SHA1

 

 

Остальные нужные опции включились сами.

Сохраним настройки, сгенерируем проект для System Workbench и откроем его там. Установим уровень оптимизации в 0 (именно в 0, так как с единичкой были некоторые проблемы), а также уберём при наличии отладочные настройки.

Проект пока не собираем, так как у нас пока нет файла fsdata.c.

 

 

Весь состав документального контента мы возьмём тот же, что и в уроке 129. Скопируем папку fs, сохранённую для данного урока, вместе с содержимым, а также файлы makefsdata.exe, makefsdata.cmd и msvcr100d.dll, чтобы мы могли свободно собирать недостающий файл с контентом, в папку «Папка с проектом//Middlewares/Third_Party/LwIP/src/apps/httpd/». Также в папку fs помести файл favicon.ico, который вы сами себе сгенерируйте под себя. Это иконка сайта, которая отображается в закладке с браузером вместе с именем документа. Если этот файл поместить, то серверу не придется постоянно отвечать браузерам об его отсутствии. Для генерации данного файла существует ряд онлайн-сервисов.

Соберём с помощью файла makefsdata.cmd файл fsdata.c, вернёмся в проект, освежим проект в дереве (Refresh) и отключим от компиляции наш файл fsdata.c.

Попробуем теперь собрать проект, проект должен будет нормально собраться.

Откроем файл main.c и подключим данные библиотеки

 

 

В функции main() изменим немного строку, выводящуюся на дисплей, для красоты

 

TFT_DisplayString(0, 10, (uint8_t *)"WebSocket Server", CENTER_MODE);

 

Удалим все инициализированные глобальные массивы строк: PAGE_HEADER_200_OK, PAGE_HEADER_SERVER, PAGE_HEADER_CONTENT_TEXT, PAGE_HEADER_CONTENT_STREAM, PAGE_HEADER_LEN, PAGE_HEADER_BYTES.

Удалим также функции DynWebPageStr и DynWebPage вместе с телами.

В функции задачи по умолчанию StartDefaultTask добавим вызов функции инициализации стека протоколов LWIP, иначе наша плата не будет даже пинговаться

 

 

Функцию tcp_thread переименуем в http_thread

 

static void http_thread(void *arg)

 

В функции задачи по умолчанию StartDefaultTask переименуем аргументы также в создании этой задачи

 

sys_thread_new("http_thread", http_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE * 4, osPriorityNormal);

 

В функции http_thread вот здесь немного убавим очередь

 

listen(sock, 5);

 

Уберём также в этой функции условия запросов файлов style.css, img01.jpg, img02.jpg, img03.jpg, img03.jpg, bg01.png, bg02.png, bg03.png, color.html, content.html и content.bin, так как таких файлов у нас теперь нет.

Добавим ещё одну глобальную структуру, а также переменную её типа

 

 

Создадим идентификатор ещё одной очереди

 

 

Выше добавим макрос её размера

 

 

 

Создадим данную очередь в функции main()

 

 

Объявим глобальный буфер для пакета WebSocket, а также выше ещё один буфер который нам тоже потребуется

 

 

Выше функции http_thread добавим функцию ещё одной задачи, в которой мы будем отправлять пакеты WebSocket клиенту

 

 

Код функции подобен коду из урока 129.

Добавим глобальный идентификатор следующей задачи

 

 

Также добавим инициализированный массив уникального идентификатора и массив для строки с хэшем

 

 

Выше функции http_thread добавим функцию ещё одной задачи, где мы будем обрабатывать трафик протокола WebSocket

 

 

Код функции также подобен применённому в уроке 129 только ориентирован уже на использование функционала API SOCKET.

Осталось нам лишь в функции http_thread своевременно создать нашу задачу

 

 

Соберём проект, прошьём контроллер и запросим главную страницу нашего сервера в браузере. В ответ мы должны будем получить вот такую страницу

 

 

Соединимся с сервером для обмена по протоколу WebSocket, нажав кнопку Connect

 

 

Кнопка превратилась в Disconnect. Нажмём её, чтобы проверить, что разъединяться мы тоже умеем

 

 

Кнопка опять превратилась в Connect и мы видим надпись, что соединение наше закрылось корректно.

Ещё раз нажмём Connect, чтобы снова соединиться с сервером, а затем нажмём верхнюю кнопку START, чтобы дать команду серверу, чтобы тот начал регулярную передачу текстовых данных в таблицу

 

 

Мы видим, что передача текстовой информации происходит отлично, а кнопка превратилась в STOP и нижняя кнопка START исчезла

 

 

Нажмём кнопку STOP и передача прекратится, а кнопка превратится опять в START и также появится внизу кнопка START, нажав на которую, мы теперь дадим серверу команду на непрерывную передачу графической информации

 

 

И вот мы видим, как раз в секунду обновляется графическая информация на странице, а кнопка START превратилась в STOP и теперь исчезла верхняя кнопка START

 

 

Остановим с помощью кнопки STOP наш график, обе кнопки START, вернутся на своё место.

Разъединимся с сервером с помощью кнопки Disconnect и попробуем немного прибавить скорость вывода графической информации.

Для этого в функции tcp_send убавим задержку в 10 раз

 

osDelay(100);

 

Соберём код, прошьём контроллер, откроем вновь нашу страницу, соединимся с сервером с помощью кнопки Connect и запустим наш график.

Всё отлично работает.

Таким образом, в данном уроке мы освоили передачу данных с сервер в браузер клиента посредством технологии WebSocket, что позволило нам также обойтись без перезагрузки всей страницы, а также мы теперь можем передавать потоки данных без запроса клиента.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

Архив файлов для сервера

 

 

Отладочную плату можно приобрести здесь 32F746G-DISCOVERY

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM LAN8742A. LWIP. SOCKET. HTTP. WebSocket

4 комментария на “STM Урок 139. LAN8742A. LWIP. SOCKET. HTTP. WebSocket
  1. mainscs:

    А Вы будете рассматривать пример с MQTT? Спасибо.

  2. raja shrama:

    hii i want to create web socket connection from my web socket server. Client is STM32 and server is on my raspbarry pi. When i send http websocket connetion request, is connected but when send data ,it's automatically disconnect. I find out this because of frame format problem. Can you please help me to how can i create frame format to transmit data to server.

  3. Vi:

    У кого на борту нет SDRAM, следует увеличить кучу во FreeRTOSе — в проекте куба или напрямую найти #define configTOTAL_HEAP_SIZE ((size_t)32768) и заменить на 65536. А то поток tcp_thread не создаётся. Спасибо видео-уроку, точнее автору. И в 129 уроке тоже увеличить кучу

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*