LINUX.ORG.RU

Архитектурно-философский вопрос

 , ,


0

2

Здравствуйте.

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

Изначально все работало на nodejs через ser2net. Сейчас переписываю на Си. Первая мысль была работать с девайсом в отдельном потоке и отдавать команды этому потоку из основного приложения

Но потом внезапно пришла вторая мысль: а почему бы не написать cli-приложение, которому в опциях командной строки передавать команду для девайса. Это приложение откроет tty, отправит команду, выдаст ответ на stdout и благополучно завершится. Затем в основном приложении вызвать popen() этого cli-приложения и читать его stdout. Особая реалтаймовость не требуется

Пожалуйста, покритикуйте вторую мысль и объясните почему я не прав и почему так делать не стоит?

★★★★★

Последнее исправление: makoven (всего исправлений: 3)

Каждую секунду девайс опрашивается

Вот по этому и не стоит. Каждую секунду запускать приложение? Зачем его тогда вообще завершать.

anonymous
()
Ответ на: комментарий от anonymous

У меня тоже первая мысль была «а не жирно ли каждую секунду запускать приложение?». А вторая мысль была «а почему-бы и нет, собственно?». А потом я задал вопрос на лоре. Собственно, этот вопрос

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 3)

Лучше демона напиши и какими-нибудь средствами IPC взаимодействуй.

С другой стороны, если у тебя нет асинхронных сообщений от железяки (т.е. она плюет в порт только в ответ на запрос) и к скорости отклика нет критических требований, то можешь и так делать. У нас многие железяки именно так и управляются: на пхытоне/IDL/чем-нибудь еще написана гуйня, как только ты какой-нибудь ползунок потрогал или данные поменял, вызывается CLI утилита с нужными параметрами и ты сразу же видишь, что произошло (т.к. ответ от нее обрабатывается и выполняются соответствующие действия). Но мне этот подход не нравится, мне больше таки нравится открыть сокет или фифо, завести буфер в SHM или даже message queue использовать, но демон держать постоянно работающим.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Меня только один момент волнует: не будет ли такой подход СИЛЬНО медленнее демона. Пока файл с програмой считается с диска, пока раскочегарится shell (вызываемый командой popen), пока откроется и сконфигурируется tty..

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Не будет: ведро обнуляет буферы лишь если ими давно никто не пользовался. А первые минут 5-10 (а то и дольше, смотря сколько у тебя оперативы и какая загруженность) твой бинарник будет в оперативе болтаться. В общем, тормозным будет только первый запуск.

раскочегарится shell (вызываемый командой popen)

Ну, это плата за popen/system. Но баш тоже болтается в оперативе.

пока откроется и сконфигурируется tty..

Это шустрей, но тоже какое-то время занимает, да. Поэтому чаще, чем раз в миллисекунд 50-100 запускать не получится.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от makoven

А зачем тебе pthreads? Запусти демона, да через фифо с ним общайся. Или через сокет, если ожидается >1 клиента... Или через message queue, если клиенты мало пишут...

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от makoven

Создаешь поток, который у нас обычно называют «кольцо» - там ты регулярно смотришь, не пришли ли данные в порт и нельзя ли их считать. Имеешь там записанные сигнатуры пакета. Задетектил начало\конец - посылаешь наверх (в другой поток, чтобы этот не тормозить), там уже парсишь готовый пакет ответа, смотришь, что там за команда пришла, имеешь обработчики. В том же кольце функция write(char * data, int size), которая пишет в порт.

Почему именно подход с «кольцом» - ты не знаешь, когда тебе придет ответ, может его совсем не будет (для этого в кольце взводится флаг таймаута и отсчитывается время. Да, ты можешь просто сделать write\wait\read, но кто гарантирует, что wait будет достаточно и что ты не порвешь пакет?

Еще в конце обычно реализуется буфер с очередью - ты же не хочешь write\write\read\read, ибо тогда нарушится очередность запрос-ответ.

Си ты вообще зря взял, там писанины на порядок больше. Если все-таки возьмешь с++, то у меня тут завалялась реализация «кольца». Документация встроенная, можешь doxygen прогнать, если так не читается. Если что - спрашивай, это моя специализация на работе - общение с устройствами через COM\LAN\USB.

sambist ★★
()
Ответ на: комментарий от Eddy_Em

А если я запущу демона не через fork/exec, а отдельно, через systemd, я смогу из другого приложения присосаться к его stdin/stdout?

makoven ★★★★★
() автор топика
Ответ на: комментарий от sambist

Когда-нибудь я тоже буду делать потоки и очереди, когда поосвоюсь с базовыми вещами)

А пока-что: делаю tcflush, посылаю команду, жду 10 секунд. Если сигнатура конца сообщения не пришла - убиваю процесс.

А «очередь» реализуется на уровне nginx. Пока fastcgi-сервис работает с tty, он не может ответить на новые запросы. Вот и вся очередь )

Общение с устройством на Си вышло в 90 строчек. Еще примерно столько же - парсер. Не особо много, на мой взгляд )

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Общение с устройством на Си вышло в 90 строчек. Еще примерно столько же - парсер. Не особо много, на мой взгляд )

жду 10 секунд.
Каждую секунду девайс опрашивается (отправляем команду получаем ответ).

Где-то вы врете.

sambist ★★
()
Ответ на: комментарий от sambist

Девайс опрашивается спустя секунду после последнего ответа. А запрос сам запрос может длиться 10. Если ответа нет - звонит sigalrm и програма завершается.

Парсер, да приврал слегка. Он еще не закончен)

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

демона
через systemd

Ты извращенец что ли? Зачем тебе поцтерошлак? Пиши init на баше и запускай через sysvinit/openrc.

я смогу из другого приложения присосаться к его stdin/stdout

В общем случае нет.

Eddy_Em ☆☆☆☆☆
()

Это какой-то ужас. Зачем такие извращения? Хочется замедлить приложение и увеличить количество причин, по которым может «что-то в программе пойти не так».

Будь мужиком и напиши программу нормально, без извращений.

pathfinder ★★★★
()
Ответ на: комментарий от anonymous

Вот по этому и не стоит. Каждую секунду запускать приложение? Зачем его тогда вообще завершать.

а потом люди критикуют systemd :)

buratino ★★★★★
()
Ответ на: комментарий от makoven

Хех. Нормально - это как?)

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

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

дать ответ коротко, двумя словами, я не смогу

Вариантов-то по пальцам пересчитать. Либо делать io в отдельном потоке. Либо в отдельном процессе (и заморачиваться с mq/IPC). Либо через асинхронщину (тысячи их - от select до libuv)

makoven ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

И как ты с ненужноD живешь?

Плыву по (модному, молодежному линукс-) течению. Батхерта не испытываю. Мой секрет успеха)

Только что осознал, что форкать вообще ничего не надо. Сделаю блокирующий fastcgi в одном потоке с tty. А опрашивает пусть браузер - посылает каждую секунду-две запрос - fastcgi проснется и отправит команду на устройство (или возмет данные из памяти если не прошло секунды с последнего обращения к tty)

makoven ★★★★★
() автор топика
Ответ на: комментарий от pathfinder

Может действительно ТС стоит поискать книжку с примерами. Архитектура приложений, завязанных на вводе/выводе - довольно обширная тема.

А можешь накидать названий книжек, если не сложно?

kravich ★★★★
()
Последнее исправление: kravich (всего исправлений: 1)

Это приложение откроет tty, отправит команду, выдаст ответ на stdout и благополучно завершится

А точно нельзя давать команды на stdin, выдавать вывод на stdout и не перезапускать приложение каждую секунду?

loz ★★★★★
()

Ну и вобще вариант с stdin/out проще для дебага и использования в других местах.

loz ★★★★★
()
Ответ на: комментарий от makoven

Меня только один момент волнует: не будет ли такой подход СИЛЬНО медленнее демона.

В таких случаях стоит тупо реализовать оба варианта и замерить.

loz ★★★★★
()

А зачем вообще выносить работу с последовательным портом в отдельный процесс, какой это даст профит в данном случае?

Проще воспользоваться select()-ом, в который будет передаваться дескриптор открытого последовательного порта и читать/писать по результатам

Harald ★★★★★
()
Ответ на: комментарий от loz

А как этот stdin/stdout читать? Делать fork/exec? Тогда на основное приложение ляжет еще и функция супервайзера, что немножко не KISS

makoven ★★★★★
() автор топика
Ответ на: комментарий от Harald

Если понадобится написать сервис с кучей девайсов на бэкенде - обязательно будет select(). А пока что думаю в сторону «один девайс - один fastcgi/http сервис». Соответственно, в браузере upyachka.ru/deivce1/{api} upyachka.ru/device2/{api}

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)

а почему бы не написать cli-приложение, которому в опциях командной строки передавать команду для девайса.

Скорее надо спращивать «а зачем писать CLI-приложение, если можно сделать библиотеку с Си-интерфейсом». В отличие от CLI, такую библиотеку несложно интегрировать во всё, что угодно.

И второе - каждый раз при запуске и завершении CLI-программы информация о состоянии устройства теряется. ХЗ, важно ли это для тебя.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Впринципе так оно сейчас и работает. Через синхронную библиотеку

makoven ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Socat

Если овалится один из концов трубы, придется убивать и второй конец и всё полностью перезапускать, правильно я понимаю?

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

Эм, также как ты планировал работать с запуском приложения каждую секунду. Не знаю насколько синхронно или асинхронно тебе надо.

loz ★★★★★
()
Ответ на: комментарий от makoven

В том что можно будет запускать программу для работы с устройством отдельно?

loz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.