Парсинг Get запроса на сервер Arduino
- Войдите на сайт для отправки комментариев
Пт, 18/10/2019 - 19:02
Добрый день,
На сервер Arduino отправляется get запрос вида:
GET /?username=Dessan&password=12345 HTTP/1.1
Сервер Ардуино принимает запрос и выводит в порт:
GET /?username=Dessan&password=12345 HTTP/1.1
Host: 192.168.0.177:5000
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 YaBrowser/19.9.3.314 Yowser/2.5 Safari/537.36
Origin: null
Accept-Encoding: gzip, deflate
Accept-Language: uk,ru;q=0.9,en;q=0.8
Я хочу, чтоб в результате get запроса я получал отдельно username, отдельно Dessan, отдельно password и отдельно 12345 и мог с этими данными что-то делать, например сравнивать и выполнять какое-либо действие.
Весь get запрос записывается в переменную tempChar но она имеет свой непонятный мне формат и как я не пытался сделать её строковой у меня ничего не вышло. Я создал другую строковую переменную readString и присвоил ей содержимое tempChar. Насколько я понял, строковые переменные в Arduino являются сами по себе массивами. После манипуляций с indexOf и substring мне удалось распарсить нужную мне строку, однако она выводит не полностью слово , к примеру, username а начинает вывод по буквам.
Вот код парсинга строки:
String readString; ... while (client.connected()) { if (client.available()) { tempChar = client.read(); //Serial.write(tempChar); if (readString.length() < 100 ) { readString += tempChar; //Serial.print(readString.length()); ind1 = readString.indexOf("?"); ind2 = readString.indexOf("="); teststring = readString.substring(ind1, ind2); teststring.replace("?", " "); teststring.trim(); ...
Вот результат парсинга (значение в teststring):
u us use user usern userna usernam username username username username username username username
и далее ещё штук 20 таких вот username
Получается , что если делать проверки содержит ли переменная username , то дальнейший код реагирует и на username и на u и на us и на use и т.д. В принципе оно работает, но хочется иметь нормальный код более менее а не совсем уже говнокод.
Сделать циклический буфер размером 8 байт, туда по кругу вносить весь приход, после каждого байта сравнивать с искомой строкой, как найдётся - поставить некий флаг что пришло и далее уже читать данные.
Читать построено до /n в буфер и так же каждую строку парсить
пытался осмыслить что хочет ТС нифига не понял
зачем в цикле приема что то искать многократно? прими весь запрос и ройся в буфере потом
чота ржу...
Переменная tempChar "неизвестного формата" :) -это один единственный символ!
Попытайтесь теперь переосмыслить свой код с учетом этой информации - может быть поймете, почему у вас строчка "username" набирается по буквам.
Как правильно делать - вам выше уже обьяснили - не хвататься распарсить каждую букву, а сначала накопить данные либо до конца строки. либо некоторое число символов. С другой стороны, пытаться вычитать весь HTPP запрос за один раз тоже не стоит, запросы бывают размером в несколько мегобайт...
тогда склеивай по символу в буфер пока в нем не появится \r\n потом парси
а так получается индексОф находит ? а второй индексОф -1 что для сабстринг вывести всю строку до конца вот она и выводит u us use user а потом еще сотню раз юсернейм целиком
Или пропускай всё до '?', потом складывай в буфер до '=' - вот тебе имя поля. Запомнил его. Пропустил '=', принимай в буфер до '&' - вот тебе значение.
Парни, спасибо за быстрые ответы, но я не понимаю как мне сделать, чтоб то что насобиралось в буфер выводилось целиком, а не по 1 букве. Я ж говорю, что String это тот же массив, а как мне объявить, чтоб то что насобиралось стало именно строкой?Какой формат мне нужно использовать? Я мучался ни один день с этим. Не понимаю как мне рыться в буфере, чтоб данные стали целостными, а не отдельными символами. Вот начиная с tempChar = client.read(); что писать, чтоб целостно выделить нужную мне информацию и уже потом её парсить? Я понимаю, что мой код - полная ерунда, это все переделанные варианты кода с разных сайтов, потому что полноценный вариант я не нашёл.
Это ж в этом примере username есть, а вообще должно распарсить любые символы начиная с /? и заканчивая HTTP/1.1, внутри разделители = и &. Например GET /?usE90ame=Des&pas2=1TY45 HTTP/1.1
Я очень надеюсь, что примерно смог пояснить, что мне нужно
Пятницо :)
Dessan - как вы предлагаете вам это обьяснить, если четыре человека предложили варианты - а вы ни один не поняли? Видимо у вас просто базовых знаний пока не хватает.
вы даже своей проблемы правильно не осознаете - она вовсе не в том что "String - это массив".
Это ж в этом примере username есть, а вообще должно распарсить любые символы начиная с /? и заканчивая HTTP/1.1, внутри разделители = и &. Например GET /?usE90ame=Des&pas2=1TY45 HTTP/1.1
Я же написал как... пропускай всё, пока tempChar != '?'. Потом складывай в строку, пока tempChar != '='. Как только tempChar == '=' - у тебя в строке уже готовое имя поля. И т.д.
Парсинг - это занятие нетривиальное, так что с наскоку ничего не выйдет.
Когда появится символ "?" начинаем вписывать всё в буфер пока не появится символ "=". По идее так?
Правда, вообще ничего не выводится теперь, но вы это имеете в виду?
По сути так, а по форме - нет. В 10-й строке новые байты из космоса берутся?
так client.read() принимает весь get запрос и посимвольно вписывает в буфер readString если условие выполняется. А как нужно?
С чего Вы взяли? Посмотрите описание функции прежде чем совать ее в свой код. А то так перепишете квартиру на ардуину.
С того, что в описании "read() считывает следующий байт, пришедший к клиенту от сервера, к которому он подключен (после последнего вызова функции read())".
Вот я беру каждый байт (т.е. символ) и присваиваю его буферу readString при выполнении условия...получаю ничего
С того, что в описании "read() считывает следующий байт
считывает байт. Один. А не весь запрос get, как вы думаете. Чтоб в tempChar появился следующий байт - надо снова вызвать процедуру read()
и так столько раз. сколько символов в запросе. На вид в вашем запросе символов этак двести - вот столько раз и надо выполнить read(). А у вас в коде сообщения #10 read() всего один - в строке 4
Да нет же, это часть кода просто. Он же и так в цикле:
Но я так понимаю, что имелось в виду, что while не подходит, потому что while выполняется пока условие True. А так как перед этим я получаю только один байт, то второй while делает бесполезную работу
Не знаю о каком втором вайле идёт речь, в приведённом коде я вижу только один (да и тот нафиг не нужен). Пятница закончилась, так что кончайте тупить и просто накапливайте свой запрос в буфере пока перевод строки не встретите. А как встретите, тогда и обрабатывайте.
да, я понял, что нужно накапливать запрос в буфере, а не знаю как мне накапливание в буфере сформулировать в виде кода. От того что вы мне ещё раз скажете, что запрос нужно накапливать в буфере до нужного символа, а потом его целиком от туда извлекать и накапливать следующий - ничего не поменяется. Я понимаю, что его нужно накапливать, я кодом не могу это записать, я не понимаю как и что для этого использовать.
я кодом не могу это записать
А словами можете?
Напишите. Примерно так
В цикле вызова loop
если пришёл символ ТО
...
если это символ есть перевод строки ТО
...
}
}
}
Можете заменить многоточия на нужные слова? Сделайте это
Dessan - так чего вы от форума ждете? Что кто-то напишет вам код? - тут это не принято
Собственно, в тех кусках, что вы уже написали - есть и прием запроса и накопление в буфере... надо только переставить строки в нужном порядке
b707, я готов не то, чтобы написать код, но показать ему как слова в код транслировать, если он напишет словами, как я просил. Потому что выражения типа "я понял но не знаю как сказать словами" на деле означают "ни хрена не понял". А вот если действительно понял и может словами сказать, что из слов код получается легко (и в разы короче и проще, чем то, что мы видм сейчас). Это я готов показать - жду "слов". Может уже не сегодня (поздно), но пусть напишет словами.
Господа учителя:
1. Почему записывается GET /? если я указываю , что начинать записывать с "?"
2. Почему не срабатывает условие для включения пина?
господин ученик...
вы в 16 строке допустили ошибку в сравнении!
садитесь - два!
без проверок на возможные ошибки просто смысл
заодно сам спрошу, какой максимальный размер буфера на стеке в ардуинке?
или так))
Как только код дойдёт до второго while, он зациклится пока второй while будет True и ничего не выдаст, потому что не будет обращения к client.read(). Об этом писал b707
По поводу буфера, если тебе поможет:
По умолчанию и для приемного и передающего буферов заданы размеры:
64 байта для микроконтроллеров с памятью свыше 1023 байта.
Для Arduino UNO R3 буферы передачи и приема имеют размер 64.
2. Если буфер переполнится, то старые данные будут потеряны.
3. Буфер находится в оперативной памяти и никак не угрожает загрузчику во Flash памяти.
Я байты/биты не понимаю вообще. Я прочитал, что 1 байт = 8 бит или 256 вариантов как записать символ, а 1 бит = 0 или 1 и в большинстве случаев 1 байтом записывают 1 символ. На этом мои познания закончены, а дальше все пишут то, что им хочется и устраивают споры на пол форума.
Dessan, начинающие, как правило, ищут простой путь, который оказывается крайне неоптимальным. Затем десятки раз всё переделывают. Большинство из нас через это прошли. Поэтому обучать Вас незамысловатым, но явно глупым приемам никто не горит желанием. А что-то нормальное Вы начинаете называть "спором на полфорума".
Поймите это и определитесь - нужна Вам нормальная помощь, для получения которой придётся скилл прокачивать или нет.
И еще: работа с микроконтроллером - это манипуляции с байтами и битами в 90% случаев. Хотите "как на пэхэпэ" - пишите на PHP.
Господа учителя:
Господин ученик, про "почему" Вам уже объяснили, но главное не в этом, а в том, что весь это Ваш развесистый код нахрен не нужен. Нужная функциональность пишется в три строки без единого while (который вообще вреден в скетчах). Но для этого надо понимать что делаете. Я Вам предложил описать словами что нужно делать (и, заодно, понять), но Вы предпочитаете упираться в неверное решение и пытаться что-то в нём подправить без понимания - дело хозяйское. Мне пофиг.
Я имел в виду, что, возможно, есть такие функции о которых я и не слышал, например нашёл sscanf. Ищу сейчас о ней документацию.
Хорошо, Евгений, давайте попробуем:
вот сам запрос GET /?usE90e=De4s&pas2=1TY45 HTTP/1.1
Dessan, удобных функций тут нет, все ручками, старайтесь не использовать тип String, помните что у вас всего 2кб ОЗУ, большие буферы сделать не получиться, сами попробуйте сделать функцию поиска подстроки в строке что бы понять как это все работает.
Вот простенький пример разбора get запроса
http://arduino.ru/forum/proekty/ethernet-vyklyuchatel-nagruzki-v-lokalno...
например нашёл sscanf.
Это над Вами на юа поглумились. Это очень капризная и сложная функция для СТРОГО определённых форматов. Вам она без надобности.
Хорошо, Евгений, давайте попробуем:
Боюсь, Вы не умеете не только программировать, но и читать. Я в #19 просил Вас расписать что нужно СЛОВАМИ без использования сущностей, которых Вы не понимаете. А Вы опять своих вайлов навалили. Скажу Вам по огромному секрету - вайл тут НАХРЕН НЕ НУЖЕН от слова "вообще".
Вы словами может расписать, что Вы собираетесь делать? Если нет, забудьте о программировании.
Собственно за разумным и функциональным решением я на форум и пришёл
Не будет никакого разумного и функционального решения пока Вы не знаете, что Вы собираетесь делать. А Вы этого не знаете. Если бы знали, то могли бы словами расписать.
Спасибо, будет что почитать ближайшую неделю,хотя бы чтоб узнать как вы столько кода уместили в ардуино.
Я во многих примерах вижу подключение библиотеки #include <string.h> для работы ф-ции strtok(). А то у меня как-то примеры даже не работают и я не нахожу библиотеку #include <string.h> .
И ещё меня интересует библиотека #include <stdio.h> , наверно её у меня тоже нет. Эти две библиотеки качаются отдельно или стандартно с ардуино устанавливаются?
Вы могли бы показать какие-то рабочие примеры с strtok() и sscanf() , чтоб я знал причина во мне или в софте.
Вы могли бы показать какие-то рабочие примеры с strtok() и sscanf() , чтоб я знал причина во мне или в софте.
ваша проблема решается в 3-5 строк безо взсяких strtok() и sscanf(), одним только чтением и сравнением символов. Если вы не знаете что такое байты и биты, то никакие функции вам не помогут
Да, я хочу только проверить у меня работают вообще strtok() и sscanf() или нет.
Да, есть у Вас и <string.h> и <stdio.h> . подключайте, работайте и не выносите мозг ни себе, ни нам.
Примеров мне не жалко, только я уже устал Вам повторять - до тех пор пока Вы не знаете что собираетесь делать, никакие волшебные библиотеки Вам не помогут. И не нужны на самом деле Вам эти функции (особенно scanf)
Вот пример с strtok - http://arduino.ru/forum/programmirovanie/parsing#comment-312218
Вот со scanf - http://arduino.ru/forum/programmirovanie/hex-string-byte-array#comment-95027
Спасибо, strtock работает, а scanf - мало того, что одни ошибки так ещё и ">>". Есть другой пример, который Вы сами писали, который без ошибок и не выглядит как "прога кул хацкера"?
Ну примеров навалом, но мне проще новый написать, чем искать :)
Сейчас чё-нить придумаю. Но, не нужна она Вам, она не для этого!
Щас чё-нить найду или напишу.
Кстати, в той моей логике не было никаких вайлов, там были if...
После всего этого обсуждения я решил вообще не ловить каждый символ в цикле while а дождаться его выполнения, то есть:
А дальше я уже думал использовать strtok() или sscanf(), но не нашёл простых рабочих примеров с этими функциями.
А ту логику, которую Вы от меня хотите добиться, я не могу осознать с точки зрения функциональности. У меня неизвестное количество параметров.
В цикле вызова loop
если пришёл символ "?" ТО
заполняем буфер
если это символ есть перевод строки ТО
прекращаем заполнять буфер, так как остальные данные нам не нужны
}
}
}
И что нам это всё даёт?
Ну, если не можете, то не можете. На нет и суда нет.
Но, пока не сможете, ничерта не получится.
Класс, работает. Теперь,я бы совместил мой код и Ваш, а перед этим нужно понять строку
const
char
* data =
"a=123&b=321&c=54&d=67"
;
А точнее этот тип данных и как этот тип данных связать с моим типом данных...
Но мне очень интересно как решить мою задачу в 3-5 строк
После всего этого обсуждения я решил вообще не ловить каждый символ в цикле while а дождаться его выполнения
это сработает при условии, что весь запрос поместится в память. А если нет - все программа развалится и ардуина зависнет. А запросы HTPP, как правило, имеют длину сотни и тысячи символов.
А выше ни один пример не показался вам "простым"? - ну так вас же предупреждали, что эти функции не для новичка
Вам в любом случае придется работать "с неизвестным числом параметров", какую бы логику вы не выбрали
Это обычный указатель на символ - используется как строка. Как Вы собрались работать с strtok и прочим добром, если Вы указателя на символ не знаете?
Чтобы решить задачу в 3-5 строк, нужно не упираться рогом, а делать что говорят. Тогда бы мы продолжили. Вы же упорно доказываете мне. что так делать не надо. Ну, если не надо, то что ж я могу сделать.
Ну, если не можете, то не можете. На нет и суда нет.
Но, пока не сможете, ничерта не получится.
Может Вы мне напишите словами, что Вы имеете в виду, а я Вам объясню почему я об этом не подумал или по какой причине решил отказаться от такого решения. Мне уже самому интересно очень что там за такое решение без использования функций
а вы уверены, что Евгению это интересно - почему вы отказались от его решения? :)) - по глупости
Мне уже самому интересно очень что там за такое решение без использования функций
код из #10. только с исправлением ошибок. какие именно ошибки - вам тоже уже сказали. Та часть, что извлекает нужные символы из строки - как раз таки всего 5 строчек
А выше ни один пример не показался вам "простым"? - ну так вас же предупреждали, что эти функции не для новичка
Все люди "уникальные", может то, что для новичка должно быть сложно, для меня наоборот легко, а сложно для меня когда вижу что-то типа ">>" или char * const , а уж совсем не регулярные выражения
Все люди "уникальные", может то, что для новичка должно быть сложно, для меня наоборот легко, а сложно для меня когда вижу что-то типа ">>" или char * const , а уж совсем не регулярные выражения
как видите - эта функция сложна не только регулярными выражениями :)
b707, у меня не повторяющиеся символы а чередующиеся = и & из постоянных только ? и новая строка
Я ничем не упираюсь, думаете я тут столько страниц текста исписал специально, чтоб ничего не делать? Я не могу понять к какой логике Вы меня подталкиваете
b707, у меня не повторяющиеся символы а чередующиеся = и & из постоянных только ? и новая строка
к чему это? не понял
Штудируйте код #10. а ошибки вам подсказал sadman41
Чтобы решить задачу в 3-5 строк, нужно не упираться рогом, а делать что говорят. Тогда бы мы продолжили. Вы же упорно доказываете мне. что так делать не надо. Ну, если не надо, то что ж я могу сделать.
Какой дурак будет упираться и писать пост №28?