Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > C++ > Qt и кроссплатформенное программирование С/С++
Регистрация

Восстановить пароль
Повторная активизация e-mail


Донат для форума - использовать для поднятия настроения себе и модераторам

А ещё здесь можно купить рекламу за 15 тыс руб в месяц! ) пишите сюда - alarforum@yandex.ru

Ответ
 
Опции темы
Старый 10.07.2019, 19:48   #1
Юрич
 
Регистрация: 02.01.2013
Сообщений: 4
Репутация: 10
По умолчанию Как инкапсулировать механизм "команда/квитанция"?

Уважаемые мидлы и сеньоры, подскажите, пожалуйста, как лучше обыграть следующую ситуацию:

Веду диалог по протоколу BINR с навигационной аппаратурой. Диалог в виде "команда/запрос - квитанция". Есть еще один нюанс - диалог через udp, т.к. между мной и аппаратурой есть посредник. Но это отражается лишь на механизме приема/отправки данных.
Хочу инкапсулировать весь этот механизм в класс - менеджер аппаратуры так, что бы снаружи остался лишь метод, например:

Код:
if(manDev.SetConnect(true)){
    // установка соединения успешно.
}
На данный момент у меня "под капотом" примерно следующий механизм (напсевдокодил):

Код:
class Manager_ports{
    QUdpSocket  *sReceive;      // принимающий сокет
    QUdpSocket  *sTransmit;     // отправляющий сокет
	
    volatile bool f_kdgConnect; // пришла квт по состоянию порта
    volatile bool f_connect;    // связь установлена
	
	// Отправка данных
    void Send_Data(QByteArray &kdg){
		sTransmit->writeDatagram(kdg.data(), kdg.size(),QHostAddress(IP), PORT);
	}
	
private slots:
    // Прием данных
    void ListenChk(){
		// создаем буфер под размер принятых данных
		QByteArray  Buffer(sReceive->pendingDatagramSize());
		sReceive->readDatagram(Buffer.data(), Buffer.size());
		
		if(KGUDPprot::ConnectPort_chk::test(Buffer)){
			KGUDPprot::ConnectPort_chk kdg(Buffer);			
			if(kdg.isConnect)	{f_connect = true;} // соединение установлено
			else				{f_connect = false;}
			f_kdgConnect = true;
		}
	}
	
public:
	Manager_ports::Manager_ports(){
		// связываем сигнал сокета со слотом чтения данных
		connect(sReceive,  SIGNAL(readyRead()), this, SLOT(ListenChk()));
	}
	
	// Установка соединения
	bool SetConnect(bool vol){
		KGUDPprot::ConnectPort_chk cmd(vol);	// Задаем состояние соединения
		f_kdgConnect 	= false;	// ожидаем квитанцию
		f_connect 		= false;	// состояние не подтверждено.
		Send_Data(cmd.encode);
		
		// Образно.
		// Пока в другом месте не придет квитанция и не поднимет флаг:
		// ждем, но не более какого-то времени.
		int t_time = 100;
		while(!f_kdgConnect && t_time){
			--t_time;
			usleep(1000);
		}
		
		// если состояние, указанное в пришедшей квитанции == заданному - успех
		// иначе (таймаут, или квт не соответствует команде) - дисконнект/неудача
		if(vol == f_connect){return true;}
		else				{return false;}
	}
}



Конечно через usleep делать - тухлый номер, но я для наглядности. Т.е. как то надо дождаться квитанции.

Я не понимаю, как в одном месте сформировать кодограмму запроса, отправить, дождаться кодограмму квитанцию в месте приёма, а в ПЕРВОМ месте сравнить два состояния и сказать получилось или нет.

Последний раз редактировалось Юрич; 10.07.2019 в 20:13.
Юрич вне форума   Ответить с цитированием
Старый 10.07.2019, 22:12   #2
Pavia
Лис
Профессионал
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 1,820
Репутация: 1956
По умолчанию

Цитата:
Сообщение от Юрич Посмотреть сообщение
Конечно через usleep делать - тухлый номер, но я для наглядности. Т.е. как то надо дождаться квитанции.
Используйте waitForReadyRead

Код:
    QByteArray buf;
    server->waitForReadyRead(TimeOut);
    if (server->pendingDatagramSize()<=0)
    {
        return false;
    }
    buf.resize(server->pendingDatagramSize());
    server->readDatagram(buf.data(),buf.size());
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia на форуме   Ответить с цитированием
Старый 11.07.2019, 07:12   #3
Юрич
 
Регистрация: 02.01.2013
Сообщений: 4
Репутация: 10
По умолчанию

Цитата:
Сообщение от Pavia Посмотреть сообщение
Используйте waitForReadyRead

Код:
    QByteArray buf;
    server->waitForReadyRead(TimeOut);
    if (server->pendingDatagramSize()<=0)
    {
        return false;
    }
    buf.resize(server->pendingDatagramSize());
    server->readDatagram(buf.data(),buf.size());
нет, так не прокатит, т.к. придти могут совсем другие данные. Например я запрашиваю настройки, стану ждать, а мне придут переодически выдаваемые данные о позиции. я побегу читать пришедшие настройки, а их нет. т.е. надо в одном месте ждать, а во втором принять, опознать именно ожидаемую квитанцию и заорать "ЗАБИРАЙ!!" (с) Няньки.
Юрич вне форума   Ответить с цитированием
Старый 11.07.2019, 11:38   #4
Pavia
Лис
Профессионал
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 1,820
Репутация: 1956
По умолчанию

Отключите все перидические передачи и работайте только по запросу.
Тогда ваш запрос никто перебить не сможет.

В противном случае.

Делаете чтение из основного потока путём ожидания события (QMutex myEvent).
Wait -функцию пишите свою с применением yieldCurrentThread.

В побочном потоке по сигналу вычитываете ваши данные и исходя из id парсети данные. Если пришли нудные то сбрасываете флаг события myEvent. В таймере побочного потока проверяете тайм аут и опять же сбрасываете флаг myEvent.

И плюс ко всему прочему баги QT, которые придётся обходить.
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia на форуме   Ответить с цитированием
Старый 11.07.2019, 12:18   #5
waleri
Профессионал
 
Регистрация: 13.07.2012
Адрес: Нижний Новгород
Сообщений: 5,849
Репутация: 1915
По умолчанию

Использования всякого рода wait и иже с ними следует избегать как огня.
На то существуют сигналы и слоты, худой конец таймеры...
waleri вне форума   Ответить с цитированием
Старый 11.07.2019, 13:57   #6
Юрич
 
Регистрация: 02.01.2013
Сообщений: 4
Репутация: 10
По умолчанию

Цитата:
Сообщение от Pavia Посмотреть сообщение
Отключите все перидические передачи и работайте только по запросу.
Тогда ваш запрос никто перебить не сможет.

В противном случае.

Делаете чтение из основного потока путём ожидания события (QMutex myEvent).
Wait -функцию пишите свою с применением yieldCurrentThread.

В побочном потоке по сигналу вычитываете ваши данные и исходя из id парсети данные. Если пришли нудные то сбрасываете флаг события myEvent. В таймере побочного потока проверяете тайм аут и опять же сбрасываете флаг myEvent.

И плюс ко всему прочему баги QT, которые придётся обходить.
если не сложно, будьте добры подсказать какую ни будь статейку с похожей реализацией? или может какой то паттерн есть? врятли моя ситуация уникальна) а с ваших слов я механизм примерно понял, но сама реализация для меня покрыта тайной))) не дорос еще немного до подобного))
Юрич вне форума   Ответить с цитированием
Старый 11.07.2019, 15:45   #7
Pavia
Лис
Профессионал
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 1,820
Репутация: 1956
По умолчанию

Юрич,
Абсолютно согласен с waleri что wait в вашей задаче совсем лишний.
Так что зачем вам вообще ожидание квитанции?
Из патернов инверсия управления(IoC) and Dependency injection (DI)

Настроили периодический пулинг. Т.е отправляете нужные запросы без всякого ожидания. По приходу датаграмы проверяете id и генерируете соответствующии им сигналы.
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia на форуме   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Убрать папки "Pictures", "Music", "Видео", "Downloads" из "МОЙ КОМПЬЮТЕР" Бахтиёр1916 Windows 1 05.04.2017 13:53
Нужно пояснить/прокомментировать код программы, или коды функций "Добавить" "Удалить" "Обновить(редактировать" "Поиск" "Период") ZIRASS PHP 4 15.06.2016 15:23
Создать класс "Вентилятор" содержащий в себе классы: "Двигатель", "Контроллер", "Пульт управления" link90 Общие вопросы C/C++ 2 27.03.2016 13:34
Механизм хранения "ключ-значение" Алексеева Евгения Помощь студентам 4 09.05.2015 00:58


11:05.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.

Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru