I'm working on a small system, it's made by several clients and one admin application. Each client has a QWebSocket server to listen admin's requests so admin app needs to connect to different clients.
This is my Login Dialog:
Before login I don't know which is client ip address so every time that I send login credentials I need try to open a connection to that IP address. The problem is that in Windows UI blocks until socket server responds or timeout its reached but in Windows its works fine.
EDIT 1: I followed Tung Le Thanh suggestions so the code includes his tips. Now the main problem is that ConnectionHelper
can't emmit any signal without getting QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
I have an ConnectionHelper
that is in charge to send an receive data to and from WebSocket setver.
main.cpp
ConnectionHelper *helper = new ConnectionHelper();
LoginDialog dialog(helper);
QThread* thread = new QThread();
helper->moveToThread(thread);
thread->start();
dialog.show();
return a.exec();
LoginDialog's constructor :
connect(helper, &ConnectionHelper::onConnectionError, this, &LoginDialog::onCxnError);
connect(helper, &ConnectionHelper::loginInformationReceived, this, &LoginDialog::onLoginInfo);
connect(helper, &ConnectionHelper::cxnEstablished, this, &LoginDialog::onConnected);
Slot on accepted:
void LoginDialog::on_buttonBox_accepted()
{
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
QString host = ui->lineEditServer->text();
QString port = ui->lineEditPort->text();
QString ws = "ws://" + host + ":" + port;
helper->setUrl(QUrl(ws));
}
void ConnectionHelper::setUrl(QUrl url)
{
if(!webSocket)
{
webSocket = new QWebSocket();
connect(webSocket, &QWebSocket::textMessageReceived, this, &ConnectionHelper::processTextMessage, Qt::QueuedConnection);
connect(webSocket, &QWebSocket::binaryMessageReceived, this, &ConnectionHelper::processBinaryMessage);
connect(webSocket, &QWebSocket::disconnected , this, &ConnectionHelper::socketDisconnected);
connect(webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error)
, this, [this](QAbstractSocket::SocketError error){
Q_UNUSED(error)
emit onConnectionError();
});
connect(webSocket, &QWebSocket::connected, this, [=]() {
emit cxnEstablished();
});
}
webSocket->open(url);
webSocket->open(url);
}
void ConnectionHelper::processTextMessage(QString message)
{
QJsonDocument response = QJsonDocument::fromJson(message.toUtf8());
QJsonObject objResponse = response.object();
QString action = objResponse[ACTION_KEY].toString();
if (action == ACTION_LOGIN)
emit loginInformationReceived(objResponse);
}
I do disable OK button until any response is received and works fine on Linux but in Windows the entire UI block and become unresponsive until a response is received.
I also try to move ConnectionHelper
instance to another Thread but I got this response: QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
I'm out of ideas I need to find a way to make webSocket->open(url)
async or any thing like that.
Thanks.
I realize that QWebSocket::open
its the only async function that I'm using. So I only need to have two threads before set the URL and open the socket connection.
Following Tung Le Thanh answers' and a little trick now everything works fine. My solution was to back to default Threat once connection is open and start to emitting signals.
void ConnectionHelper::setUrl(QUrl url, QThread* thread)
{
if(!webSocket)
{
webSocket = new QWebSocket();
connect(webSocket, &QWebSocket::connected, this, [this, thread]() {
this->moveToThread(thread);
webSocket->moveToThread(thread);
emit this->cxnEstablished();
});
}
webSocket->open(url);
}
And now LoginDialog
needs to send it's Thread
void LoginDialog::on_buttonBox_accepted()
{
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
QString host = ui->lineEditServer->text();
QString port = ui->lineEditPort->text();
QString ws = "ws://" + host + ":" + port;
QMetaObject::invokeMethod( helper, "setUrl", Qt::QueueConnection,
Q_ARG( QUrl, QUrl(ws)),
Q_ARG( QThread*, QThread::currentThread())
);
}