Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

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

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

Купить рекламу на форуме - 42 тыс руб за месяц

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

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

Веду диалог по протоколу 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 в 19:13.
Юрич вне форума Ответить с цитированием
Старый 10.07.2019, 21:12   #2
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Цитата:
Сообщение от Юрич Посмотреть сообщение
Конечно через 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, 06:12   #3
Юрич
 
Регистрация: 02.01.2013
Сообщений: 4
По умолчанию

Цитата:
Сообщение от 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, 10:38   #4
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

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

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

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

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

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

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

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

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

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

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

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

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

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


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


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