Название: [РЕШЕНО] QtWebsocket синхронный вызов Отправлено: Nimbus от Июнь 19, 2013, 10:56 Ох давно я уже на С++ и Qt ничего не делал...
Внезапно для одного веб-проектика понадобилось реализовать B2B мини десктоп приложения в трее, которое бы коннектилось по вебсокету к Node.js (используется node-модуль ws). Суть в том, чтобы Node.js периодически отправлял уведомления, а приложение нотифицировало пользователя. Нашёл на гитхабе (https://github.com/ant-lafarge/QtWebsocket) небольшую либу, реализующую данный протокол. Все данные от сервера идут в формате JSON обычной строкой. Если сильно утрировано без сложноты, то примерный код выглядит так: Код Всё работает, всё ништяк, данные приходят и появляется уведомление. Теперь необходимо реализовать некое подобие RPC при определённом действии пользователя. То есть, реализовать синхронные вызовы на клиенте. То есть, отправлять данные в формате JSON, ожидать ответа именно на данный запрос, при этом не терять обычные уведомления. К каждому запросу клиента прикрепляется некий ID, генерящийся на клиенте и возвращающийся сервером вместе с ответом, так что проблема с идентификацией запрос : ответ частично решена. Остаётся вопрос синхронности, блокирующей главный поток на время обработки сервером запроса. Банально есть Код ответ придёт и вызовется слот messageReceived, но вызовется в главном потоке. Так что, мне нельзя организовать цикл while(true) в методе sendMessage после отправки. Пробовал так: Код Но это всё дело крашится с сегфолтом при вызове waitForReadyRead, а Node.js'у ничего не приходит и происходит сразу дисконнект сокета. Как решить данную проблему синхронного вызова? Было бы идеально, если бы слот messageReceived вызывался в другом потоке, но QThread::getCurrentThreadId() при отправке и при получений одинаковый. Или может есть более элегантные решения? Название: Re: QtWebsocket синхронный вызов Отправлено: dio от Июнь 19, 2013, 15:05 Организуйте очередь запросов. Не сразу отправляйте запрос, а ставите его в очередь пока не придет ответ на предыдущей запрос. Ответ пришел, отправляйте следующей запрос.
Название: Re: QtWebsocket синхронный вызов Отправлено: Nimbus от Июнь 19, 2013, 15:46 Организуйте очередь запросов. Не сразу отправляйте запрос, а ставите его в очередь пока не придет ответ на предыдущей запрос. Ответ пришел, отправляйте следующей запрос. Идея хорошая, но, поскольку, отправка данных и приём варятся в одном потоке, то как мне банально вызвать блокировку потока (?) при двух последовательных вызовах типаКод ? P. S. у меня есть подозрение, что эту магию можно кастовать через QEventLoop... Название: Re: QtWebsocket синхронный вызов Отправлено: dio от Июнь 19, 2013, 17:30 Не могу понять, зачем Вам блокировать поток? Если запросы будут отправляться последовательно, то и ответы должны приходить последовательно.
Название: Re: QtWebsocket синхронный вызов Отправлено: Nimbus от Июнь 19, 2013, 17:47 Не могу понять, зачем Вам блокировать поток? Если запросы будут отправляться последовательно, то и ответы должны приходить последовательно. Да, но ведь, помимо ответов могут ещё идти простые уведомления. Вдруг такое уведомление попадёт в промежуток между запросом и ответом. К тому же, спорный вопрос насчёт "последовательные вопросы - последовательные ответы"Название: Re: QtWebsocket синхронный вызов Отправлено: dio от Июнь 19, 2013, 17:59 Уведомления кэшируйте.
Цитировать К тому же, спорный вопрос насчёт "последовательные вопросы - последовательные ответы" Если Вы имеете в виду отсутствие ответа и случайные запросы, то эту ситуацию можно обработать. Название: Re: QtWebsocket синхронный вызов Отправлено: Nimbus от Июнь 19, 2013, 18:42 Уведомления кэшируйте. Цитировать К тому же, спорный вопрос насчёт "последовательные вопросы - последовательные ответы" Если Вы имеете в виду отсутствие ответа и случайные запросы, то эту ситуацию можно обработать. Да про кэширование это и так ясно. Вопрос-то не в этом :) А в том "как добиться работы такого кода: QJsonDocument res1 = manager->sendMessageSync(msg1);, когда внутри метода sendMessageSync вызывается асинхронный socket->write(), но нет ничего что блокировало бы поток чтобы дождаться нужного ответа и вернуть из метода экземпляр QJsonDocument, полученный в ответе в виде JSON'а?" Название: Re: QtWebsocket синхронный вызов Отправлено: Kurles от Июнь 19, 2013, 18:59 Уведомления кэшируйте. Цитировать К тому же, спорный вопрос насчёт "последовательные вопросы - последовательные ответы" Если Вы имеете в виду отсутствие ответа и случайные запросы, то эту ситуацию можно обработать. Да про кэширование это и так ясно. Вопрос-то не в этом :) А в том "как добиться работы такого кода: QJsonDocument res1 = manager->sendMessageSync(msg1);, когда внутри метода sendMessageSync вызывается асинхронный socket->write(), но нет ничего что блокировало бы поток чтобы дождаться нужного ответа и вернуть из метода экземпляр QJsonDocument, полученный в ответе в виде JSON'а?" Название: Re: QtWebsocket синхронный вызов Отправлено: Nimbus от Июнь 19, 2013, 19:04 Еще раз - зачем блокировать поток? вызвали write(), завели таймер на время, которого заведомо должно хватить на ожидание ответа, отдали управление евентлупу. Затем в слоте, привязанному к readyRead(), останавливаем таймер, читаем ответ, и если это не уведомление, то переходим к следующему сообщению в очереди, иначе заново заводим таймер и продолжаем ждать ответ. Если слот, привязанный к таймеру успевает выполниться - беда, сервер не отвечает, тоже каким-либо образом эта ситуация обрабатывается. Упрощенно так. Можно еще что-то типа конечного автомата с его состояниями прикрутить. Вот примерно такого ответа я и ожидал. Видимо, как я уже и думал, нужно использовать QEventLoop, если нет других решений. Спасибо за подробный ответ :) А state machine у меня уже реализован. Название: Re: QtWebsocket синхронный вызов Отправлено: Nimbus от Июнь 20, 2013, 08:22 Увы, оказалось всё не так-то просто. Сигнал readyRead() не вызывается у сокета никогда в случае если использовать QEventLoop::exec (или qApp->processEvents() в бесконечном цикле). Хоть данные на сервер и приходят, ответ отправляется, но readyRead не сигналит никак.
Повторюсь, делаю всё в одном потоке, дабы не извращаться с потоками и (о, ужас) с блокировками. Upd: мды... Решилось всё экспериментальным путём со сменой ConnectionType'а, вместо Qt::AutoConnection поставил Qt::QueuedConnection. Название: Re: QtWebsocket синхронный вызов Отправлено: Kurles от Июнь 20, 2013, 10:34 Увы, оказалось всё не так-то просто. Сигнал readyRead() не вызывается у сокета никогда в случае если использовать QEventLoop::exec (или qApp->processEvents() в бесконечном цикле). Хоть данные на сервер и приходят, ответ отправляется, но readyRead не сигналит никак. Опять же не понятно, зачем QEventLoop::exec() или qApp->processEvents() в бесконечном цикле использовать )Повторюсь, делаю всё в одном потоке, дабы не извращаться с потоками и (о, ужас) с блокировками. Название: Re: QtWebsocket синхронный вызов Отправлено: Nimbus от Июнь 21, 2013, 16:55 Опять же не понятно, зачем QEventLoop::exec() или qApp->processEvents() в бесконечном цикле использовать ) QEventLoop::exec() безо всяких циклов =) |