Russian Qt Forum

Qt => Общие вопросы => Тема начата: sergek от Июнь 17, 2014, 10:06



Название: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 17, 2014, 10:06
Коллеги, подскажите, пожалуйста, как организуется ожидание данных в асинхронном режиме?
Задача - взаимодействие по типу запрос/ответ с устройством (контроллером) через сокет. Есть функция, которая выполняет передачу запроса в сокет (функция запроса). Чтение ответа от контроллера выполняется асинхронно, по сигналу readyRead (обработчик ответа).
Мне нужно в функции запроса дождаться ответа железяки, прочесть его и отправить куда надо. Т.е. в функции нужно организовать ожидание и фиксацию завершения работы обработчика ответа. Как передать данные - отдельный вопрос, и речь не о нем.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Bepec от Июнь 17, 2014, 11:00
Так может вам синхронный режим нужен?


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 17, 2014, 11:09
Нет. Режим многопользовательский, время ответа у разных устройств - разное. Поэтому, пока я жду своего ответа, другие клиенты могут получить свои.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Bepec от Июнь 17, 2014, 11:40
Стоп.

Вы уж определитесь - в функции запроса дождаться ответа железяки. И как вы в этот момент примите другие кадры? насколько я понимаю вы из ф-ции выходить не хотите, потому никак, скорее всего :)



Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Igors от Июнь 17, 2014, 12:02
Ну хотя бы повиснуть на мутексе (а может еще лучше на семафоре), который асинхронка откроет. Или я чего-то не понял в вопросе 


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Hellraiser от Июнь 17, 2014, 12:34
После отправки запроса запускаем разовый сторожевой таймер. Время ожидания должно определяться в протоколе обмена с контроллером. Сработал таймер - значит контроллер не ответил за заданное время, ответил контроллер до срабатывания - останавливаем таймер (если есть объект) или ставим флаг игнорирования (для статического QTimer::singleShot), который обрабатываем в слоте таймера. Только при приеме данных надо помнить о том, что данные могут приходить порциями, т.е. остановка таймера только после чтения полного ответа.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 17, 2014, 13:14
Вы уж определитесь - в функции запроса дождаться ответа железяки. И как вы в этот момент примите другие кадры? насколько я понимаю вы из ф-ции выходить не хотите, потому никак, скорее всего :)
Собственно, чего темнить - обмен по modbus TCP. Задумка была такая - запросы клиенты передают запросы каждый в своем порожденном процессе. Т.е., подключился к контроллеру, передал, отключился. И ждет некоторое время.
А все ответы получает основной процесс по 502-му порту и складывает в кучку, например, в БД. Вот клиентский процесс должен подождать, когда его ответ появится и забрать.
Возможно, я ошибаюсь - хотел потом проверить. Контроллер можно настроить на любой порт, но сервер всегда должен слушать 502-й. Вот это я и хотел использовать.
Есть, конечно, другое решение - два последовательных запроса (передача запроса, потом получение ответа).


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: qate от Июнь 17, 2014, 14:54
Собственно, чего темнить - обмен по modbus TCP.

читай спецификацию modbus TCP, может так и невозможно сделать


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Hellraiser от Июнь 17, 2014, 15:15
С контроллером (железякой) должен общаться только программный сервер в режиме "Master-Slave", причем мастер - это сервер. Он же по сети принимает запросы от всех клиентов и формирует очередь запросов к контроллеру. После исполнения запроса контроллером происходит анализ ответа и определение клиента, пославшего этот запрос. И только этому клиенту отправляется ответ (или уведомление о таймауте его запроса). Железяка все-равно не будет исполнять запросы параллельно.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Hellraiser от Июнь 17, 2014, 15:19
Складывать запросы от клиентов в БД - очень плохая идея. Выполненный запрос никому уже не нужен, следовательно БД будет постоянно модифицироваться и времени на дисковые операции ох как много уйдет. Гораздо эффективнее использовать что-то типа QQueue<QByteArray> с контролем размерности. К примеру, ограничить на 1000 элементов, а при достижении потолка тормозить клиентов.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 17, 2014, 16:48
читай спецификацию modbus TCP, может так и невозможно сделать
Может и нельзя.
Цитировать
The listening TCP port 502 is reserved for MODBUS communications. It is mandatory to listen by default on that port. However, some markets or applications might require that another port is dedicated to MODBUS over TCP. For that reason, it is highly recommended that the clients and the servers give the possibility to the user to parameterize the MODBUS over TCP port number. It is important to note that even if another TCP server port is configured for MODBUS service in certain applications, TCP server port 502 must still be available in addition to any application specific ports.
А я разве задавал вопрос о том, можно ли так сделать? Контроллеры бываю разные...


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 17, 2014, 17:01
После исполнения запроса контроллером происходит анализ ответа и определение клиента, пославшего этот запрос. И только этому клиенту отправляется ответ (или уведомление о таймауте его запроса).
Немного не так. Контроллер тупо транслирует запрос в сеть RS-485. То устройство, которому он адресован, его исполняет и отвечает в соответствии с спецификацией функции. Контроллер просто передает ответ обратно в сеть TCP/IP.
Какому клиенту передать ответ, решает сервер - запрос и ответ имеют для этого идентификатор транзакции. Собственно, мой вопрос и касался того, как мне лучше замкнуть транзакцию.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 17, 2014, 17:43
Складывать запросы от клиентов в БД - очень плохая идея. Выполненный запрос никому уже не нужен...
Почему же не нужен? Ответы на запросы определенного типа (например, получить состояние устройства) очень даже нужны - они описывают текущее состояние системы.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Hellraiser от Июнь 17, 2014, 18:44
Результат выполнения запроса нужен, но только результат, а не сам запрос. Для модбаса запрос - номера функции или регистров устройства, зачем хранить этот байтовый набор? А вот результат, описывающий состояние системы, - однозначно нужен. А 485 интерфейс вообще полудуплексный - одновременно болтать и слушать не получится.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Bepec от Июнь 17, 2014, 19:35
Если у вас RS485, то у вас должно быть временное окно для кадра. Значение, при котором устройство считается недоступным. И у вас получается синхронная работа, ведь RS485, как правильно замечено, может обеспечивать одномоментную передачу лишь одного кадра.

Не вижу проблемы. У меня был тупо QEventLoop c таймером в 500 мс. Если за 500 мс не пришёл ответ - следующий запрос, текущее устройство недоступно.


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 17, 2014, 22:19
Не вижу проблемы. У меня был тупо QEventLoop c таймером в 500 мс. Если за 500 мс не пришёл ответ - следующий запрос, текущее устройство недоступно.
Спасибо!


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Bepec от Июнь 18, 2014, 02:55
Как бы не за что, но это изврат на самом деле :D

Асинхронная передача с циклом, с таймером, превращаемая в синхронную :D

PS я пользуюсь :D


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: sergek от Июнь 18, 2014, 19:52
Как бы не за что, но это изврат на самом деле :D
Асинхронная передача с циклом, с таймером, превращаемая в синхронную :D
Наоборот, мне понравилось. Я напомню - у меня два разных процесса, один пишет в БД, второй - читает то, что пишет первый. Первый дописал, дал сигнал. Второй по этому сигналу прочел данные и завершился. Предельное время ожидания задается таймером, для случаев, когда первый загнется.
Код:
    QEventLoop loop;
    QTimer::singleShot(500, &loop, SLOT(quit()));
    connect(this,SIGNAL(transComplete()), &loop,SLOT(quit()));
    loop.exec();
Все красиво, и, главное, просто. Правда, не знаю, можно ли сигналы Qt передавать между процессами linux. Но, думаю, это решается, если не так, то по-другому.

PS Кстати, вспомнил про Unix-сокеты (AF_UNIX).


Название: Re: Ожидание данных в асинхронном режиме
Отправлено: Bepec от Июнь 18, 2014, 21:02
Передавать нельзя напрямую, но есть библиотеки на qt-project которые позволяют это делать даже через tcp :)