STM Урок 129. LAN8742A. LWIP. NETCONN. HTTP. WebSocket. Часть 1



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

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

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

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

Специфика технологии WebSocket такова. Мы из браузера шлём запрос на соединение с целью создания сокета с помощью пакета HTTP с определённым содержимым. Только шлём мы его уже не по тому адресу, куда мы обращаемся для загрузки всего нашего HTTP-содержимого. IP-адрес может быть и тем же, как будет в нашем случае, но тогда с этой целью на сервере должен быть открыт, то есть должен прослушиваться ещё один порт. Клиент пытается с этим адресом и портом соединиться и при успешном соединении он шлёт этот самый запрос с целью создания сокета. Сервер видит этот запрос и генерирует ответ клиенту, что он может (ну или не может) создать такое соединение. И затем в случае такого положительного ответа сервера клиенту между ними считается созданным (открытым) тот самый веб-сокет и они уже могут спокойно слать друг другу какие-либо (ну конечно тоже как-то немного структурированные) порции данных в любое время, независимо от того, просит ли это другая сторона.

Протокол обмена WebSocket имеет стандарт RFC 6455. В соответствии с данным стандартом в клиент генерирует некий ключ, состоящий из символов, длиной 24 символа.

Затем сервер берёт этот ключ, присоединяет к нему идентификатор GUID, имеющий стандартное значение, никогда не изменяемое — «258EAFA5-E914-47DA-95CA-C5AB0DC85B11» длиной 36 символов. Получается уже строка общей длиной 60 символов. Затем по алгоритму SHA1 сервер получает хэш данной строки длиной 20 символов, а затем уже этот хэш прогоняет по алгоритму Base64, то есть кодирует его. И затем уже в ответном пакете эту полученную закодированную строку отправляет клиенту.

Клиент, в свою очередь, также «смотрит» данную закодированную строку и проверяет, из его ли отправленной строки она получена. Если это так, то соединение считается установленным. Если нет, то клиент тут же разрывает соединение.

Немного подробнее протокол запроса и ответа на создание сокета, да и не только на создание, мы увидим чуть позже, в момент написания кода, так как мы уже давно убедились, что это намного результативнее. А сейчас мы начнём создавать наш проект, который был сделан из проекта прошлого занятия с именем LAN8742_HTTP_SERVER_AJAX_NETCONN и назван вот так: LAN8742_WEBSOCKET_NETCONN.

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

Во-первых, некоторыми контроллерами STM алгоритм хеширования и кодирования вышеперечисленными стандартами поддерживается аппаратно. Но, так как в разделе Pinout у нас отсутствует ветка HASH, значит нашему контроллеру не повезло. Но разработчики проектогенератора Cube MX пошли нам навстречу и добавили библиотеку, которая позволяет сделать это программно, то есть не писать самим данные алгоритмы. Причём эта библиотека поддерживает превеликое множество таких разнообразных стандартов. Вот мы и включим её

Включим также остальные банки памяти SDRAM

Соответственно, в разделе Configuration мы в настройках Cortex M7 добавим эту память

Зайдём в настройки LWIP и в разделе Key Options убавим обратно размер стека на процесс TCP/IP, иначе на все задачи его может не хватить.

А ещё проще сбросить настройки LWIP по умолчанию

Сначала, как всегда, отключим DHCP и настроим статическую адресацию

Осталось нам здесь только включить HTTPD

Теперь идём в настройки FREERTOS и немного убавим стек также и для задачи по умолчанию, чтобы было ровно 4 килобайта (у нас стек в словах, значит умножаем на 4)

 

 

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

Во вкладке Config parameters добавим ещё немного размер кучи. Размер я подобрал экспериментально. Если оставить прежний, то может не хватить, а если добавить ещё больше, то не работает

Здесь уже размер в байтах и это составляет ровно 32 килобайта.

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

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

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

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

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

 

 

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

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

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

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

Больше ничего и нигде включать не надо.

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

Проект пока не собираем.

Подготовим файл странички с именем index.html следующего содержания и сохраним её по уже давно известному нам пути

 

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

Также мы подготовили место для кода JavaScript, стили для элементов мы также прописали внутри файла главного документа, так как их сегодня немного, да и почему-то подключение множества файлов при наличии второго соединения идёт туговато. Также у нас не будет никаких хедеров, футеров и сайдбаров. Мы с ними наигрались в прошлом уроке. В нашем документе только поле для текстовой информации пока без кнопки, чтобы мы её случайно не нажали до установки соединения, а также поле для вывода графика также пока без кнопки. Также сверху имеется поле для вывода информации некоторых состояний нашего соединения с идентификатором status.

Также не забудем поместить в папку с нашей страницей файл 404.html.

Соберём сначала файл fsdata.c, обновим дерево проекта (или освежим), запретим данному файлу компилироваться, и пока также не собираем проект, так как он все равно не соберётся из-за задачи по выводу на печать. Она же теперь ещё у нас создаётся и автоматически. Поэтому сначала удалим объявление её идентификатора

osThreadId TaskStringOutHandle;

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

 

Пригодятся ещё и вот эти

 

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

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

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

Также удалим создание задачи

osThreadDef(tskstrout, TaskStringOut, osPriorityBelowNormal, 0, 1280);

TaskStringOutHandle = osThreadCreate(osThread(tskstrout), NULL);

Удалим задачу TaskStringOut вместе с телом, соответственно, в том месте, где мы её добавляли сами.

Также, чтобы освободить кучу, мы воспользуемся памятью SDRAM, все равно он у нас пустует. Я сначала хотел в обычной оперативной памяти динамически запрашивать место под массивы, а потом его освобождать, но это тоже не совсем безопасно, так как оставшийся размер кучи можно будет не совсем корректно вычислить. Может случиться такая ситуация, когда несколько задач одновременно запросят память, у нас же всё-таки многозадачная система.

Поэтому для массивов, которые нам будут нужны впоследствии мы добавим пока только глобальные указатели

 

А вот эти массивы удалим

 

char str1[60];

char str_buf[1000]={'\0'};

 

А в функции main() мы выделим под наши массивы место в памяти SDRAM

 

Дальнейший код писать мы продолжим в следующей части занятия, в которой мы создадим ряд задач и научимся отвечать клиенту на запрос соединения WebSocket.

 

 

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

 

 

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

 

 

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

 

STM LAN8742A. LWIP. NETCONN. HTTP. WebSocket

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

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

*