Название: Проектирование приложения Отправлено: PazDim от Май 25, 2019, 17:51 Добрый день. Нужна помощь - не понимаю архитектуры приложений для QT. В книжке написано, что библиотека использует слоты и сигналы, мол это лучше, чем callback. Но что делать с программами, которые не предполагают использования сигналов? Сейчас стоит задача в работе по TCP - необходим автомат, который принимает данные, обрабатывает и отправляет ответ (просто бесконечный цикл, опрашивающий сокет и отправляющий в него данные). У QTcpSocket чтение данных выполняется через сигналы. Попробовал вынести его в отдельный поток (основной занят автоматом и выполняения event loop не предполагает) - сигнал Connected генерируется, ReadyRead вроде тоже, но не могу нормально писать - write приходится вызывать из основного потока, ругается. Плюнул, попробовал следующий код:
Код: #include <QTcpSocket> Сокет постоянно находится в состоянии попытки соединения, то есть ему даже для соединения нужен Event Loop? Как уже писал, основной цикл не предполагает передачи управления QT, лепить в каждую итерацию обработку сигналов тоже не хочется. Помню, что когда-то получилось работать по сети без сигналов, но выглядело и работало очень криво. Если идея бесконечного цила неверная, то как правильно проектировать программу? Обычное консольное приложение, не думал что так голова будет болеть. Название: Re: Проектирование приложения Отправлено: PazDim от Май 25, 2019, 18:40 Заменить бесконечный цикл таймером в одну миллисекунду и лепить все в одном потоке - это правильно?
Название: Re: Проектирование приложения Отправлено: PazDim от Май 26, 2019, 11:01 Блин, в таймере получается здоровенный автомат с кучей кейсов. Логика вроде "отправить запрос, подождать ответа, обработать, отправить следующий, подождать" на сигналы-слоты совсем не ложится. Пока вижу решение как добавление отдельного потока, который не будет иметь цикла событий и будет вызывать слоты других классов с помощью QMetaObject::invokeMethod. Это нормальный подход?
Название: Re: Проектирование приложения Отправлено: sergek от Май 26, 2019, 12:23 Если ваша программа только принимает данные и отправляет ответ, то вообще никакого цикла и таймера не нужно. И уж, конечно, не нужны потоки.
Создаете сокет, соединяете его сигнал readyRead со своим слотом, в котором обрабатываются полученные данные. В нем реализуете логику определения того, что нужные данные получены (по размеру или признакам начала/конца). Скорее всего, понадобится буфер, куда записываете полученные данные. В этом слоте реализуете запись в сокет ответа после того, как все данные получите. Не забудьте эти данные из буфера удалить. Потом сокет подключаете (connectToHost) к порту и все. Название: Re: Проектирование приложения Отправлено: PazDim от Май 26, 2019, 13:24 Если ваша программа только принимает данные и отправляет ответ, то вообще никакого цикла и таймера не нужно. И уж, конечно, не нужны потоки. Не все алгоритмы ложатся на такую структуру.Создаете сокет, соединяете его сигнал readyRead со своим слотом, в котором обрабатываются полученные данные. В нем реализуете логику определения того, что нужные данные получены (по размеру или признакам начала/конца). Скорее всего, понадобится буфер, куда записываете полученные данные. В этом слоте реализуете запись в сокет ответа после того, как все данные получите. Не забудьте эти данные из буфера удалить. Потом сокет подключаете (connectToHost) к порту и все. Отправить команду А. Подождать, пока не придет ответ Б. Отправить команду В. Подождать, пока не придет ответ Г. Разделять их на разные слоты слишком сложно - иногда приходится ждать дополнительного условия. Нужно накручивать таймеры для таймаутов. Название: Re: Проектирование приложения Отправлено: sergek от Май 26, 2019, 14:43 Из постановки следовало только то, что программ должна отвечать на поступающие данные.
Если требуются запросы с ожиданием ответа, то можно после запроса организовать ожидание в цикле обработки событий. Этот цикл должен завершаться по по вашему сигналу, испускаемому из слота после получения данных, ну и по заданному таймауту. А запросы, как вы и писали, можно делать по таймеру. Название: Re: Проектирование приложения Отправлено: Авварон от Май 26, 2019, 16:58 Посмотрите на waitForConnected и waitForReadyRead
Название: Re: Проектирование приложения Отправлено: PazDim от Май 26, 2019, 17:16 Буду привыкать к сигналам-слотам. Посмотрим, что из этого получится.
Название: Re: Проектирование приложения Отправлено: Авварон от Май 26, 2019, 20:23 Сигнал-слоты всегда можно завернуть в синхронку с помощью QFuture/QFutureInterface. Я так недавно делал с QNetworkAccessManager'ом - мне надо было сделать синхронную функцию "скачай файл и положи сюда". Сделал тред с эвентлупом и завернул в футуру метод: QFuture<bool> download(QUrl src, QString dst).
Название: Re: Проектирование приложения Отправлено: PazDim от Май 26, 2019, 20:29 Спасибо, почитаю, что за звери. Пока остановился на таймерах и автоматах.
|