Qt QWebsocket::open blocks user interface












0















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:



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.










share|improve this question

























  • Hi there, not sure if this helps or not, but have you tried QCoreApplication::processEvents()?

    – TrebuchetMS
    Nov 22 '18 at 15:18











  • Hi, you can capture this in lambda and use emit this->cxnEstablished(); to see if it works. Note that setUrl must be invoke form invokeMethod, not being called from UI thread.

    – tunglt
    Nov 22 '18 at 18:58











  • Didn't work... and yes, I use your suggestion QMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))

    – Engel
    Nov 22 '18 at 19:18
















0















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:



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.










share|improve this question

























  • Hi there, not sure if this helps or not, but have you tried QCoreApplication::processEvents()?

    – TrebuchetMS
    Nov 22 '18 at 15:18











  • Hi, you can capture this in lambda and use emit this->cxnEstablished(); to see if it works. Note that setUrl must be invoke form invokeMethod, not being called from UI thread.

    – tunglt
    Nov 22 '18 at 18:58











  • Didn't work... and yes, I use your suggestion QMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))

    – Engel
    Nov 22 '18 at 19:18














0












0








0








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:



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.










share|improve this question
















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:



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.







c++ qt qtwebsockets






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 18:11







Engel

















asked Nov 22 '18 at 14:54









EngelEngel

2118




2118













  • Hi there, not sure if this helps or not, but have you tried QCoreApplication::processEvents()?

    – TrebuchetMS
    Nov 22 '18 at 15:18











  • Hi, you can capture this in lambda and use emit this->cxnEstablished(); to see if it works. Note that setUrl must be invoke form invokeMethod, not being called from UI thread.

    – tunglt
    Nov 22 '18 at 18:58











  • Didn't work... and yes, I use your suggestion QMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))

    – Engel
    Nov 22 '18 at 19:18



















  • Hi there, not sure if this helps or not, but have you tried QCoreApplication::processEvents()?

    – TrebuchetMS
    Nov 22 '18 at 15:18











  • Hi, you can capture this in lambda and use emit this->cxnEstablished(); to see if it works. Note that setUrl must be invoke form invokeMethod, not being called from UI thread.

    – tunglt
    Nov 22 '18 at 18:58











  • Didn't work... and yes, I use your suggestion QMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))

    – Engel
    Nov 22 '18 at 19:18

















Hi there, not sure if this helps or not, but have you tried QCoreApplication::processEvents()?

– TrebuchetMS
Nov 22 '18 at 15:18





Hi there, not sure if this helps or not, but have you tried QCoreApplication::processEvents()?

– TrebuchetMS
Nov 22 '18 at 15:18













Hi, you can capture this in lambda and use emit this->cxnEstablished(); to see if it works. Note that setUrl must be invoke form invokeMethod, not being called from UI thread.

– tunglt
Nov 22 '18 at 18:58





Hi, you can capture this in lambda and use emit this->cxnEstablished(); to see if it works. Note that setUrl must be invoke form invokeMethod, not being called from UI thread.

– tunglt
Nov 22 '18 at 18:58













Didn't work... and yes, I use your suggestion QMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))

– Engel
Nov 22 '18 at 19:18





Didn't work... and yes, I use your suggestion QMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))

– Engel
Nov 22 '18 at 19:18












2 Answers
2






active

oldest

votes


















1














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())
);
}





share|improve this answer
























  • I'm happy that you have found the solution. I posted also mine that I've used for the test.

    – tunglt
    Nov 22 '18 at 21:31











  • It's nice to see webSocket can move to another thread that way.

    – tunglt
    Nov 22 '18 at 21:42











  • I think found the source of the problem, the code now can work without tricks.

    – tunglt
    Nov 23 '18 at 9:45



















0














The error :




QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread




occurred while you try to call a network function directly from another thread (helper and its webSocket were in the other thread). Use invokeMethod or signal/slot instead.



EDIT 1 : in fact, the webSocket was created while ConnectionHelper constructor was called, and its belong to the main thread. The moveToThread does not allow the webSocket to be moved if ConnectionHelper was not set as its parent. To avoid that, the webSocket must be initialized with ConnectionHelper as a parent or when the thread was already started.



NOTE: if your application quits just after the dialog accepted() was fired (main window closed), you cannot see your signals emited.



UPDATE 2



    ConnectionHelper::ConnectionHelper(QObject *parent) : QObject(parent)
{
webSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);

connect( webSocket, &QWebSocket::stateChanged, this, [=](QAbstractSocket::SocketState s){
qDebug() << "Socket state changed : " << s;
} );
connect( webSocket, &QWebSocket::connected, this, [=](){
emit cxnOk();
webSocket->sendTextMessage("HELLO");
} );

void (QWebSocket::*error_signal)(QAbstractSocket::SocketError err) = &QWebSocket::error;

connect( webSocket, error_signal, this, [=](QAbstractSocket::SocketError err){
qDebug() << "On socket error : " << err;
} );

connect( webSocket, &QWebSocket::textMessageReceived, this, [=](QString s){
qDebug() << "text message received: " << s;
} );
}

void ConnectionHelper::setUrl(QUrl url)
{
if( webSocket->state() == QAbstractSocket::ConnectedState ){
webSocket->close();
}

qDebug() << "Open URL: " << url;
webSocket->open( url );
}


Initialization of ConnectionHelper instance :



    QThread * pThread = new QThread();
m_pHelper = new ConnectionHelper();

connect( m_pHelper, &ConnectionHelper::cxnOk, this, &MainWindow::onConnectionConnected, Qt::QueuedConnection );

m_pHelper->moveToThread( pThread );
pThread->start();


Change setUrl to slot then use invokeMethod to send the command to the helper instance.



    void MainWindow::on_pushButton_clicked()
{
QString ws = "ws://echo.websocket.org";
QMetaObject::invokeMethod( m_pHelper, "setUrl", Qt::QueuedConnection, Q_ARG( QUrl, QUrl(ws) ) );
qDebug() << "Invoke setUrl ended" ;

}

void MainWindow::onConnectionConnected()
{
qDebug() << "[MainWindow] On connection connected !!!!";
}


RESULTS:



    Invoke setUrl ended
Open URL: QUrl("ws://echo.websocket.org")
Socket state changed : QAbstractSocket::ConnectingState
Socket state changed : QAbstractSocket::ConnectedState
[MainWindow] On connection connected !!!!
text message received: "HELLO"





share|improve this answer


























  • I did it but still having the same warning QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    – Engel
    Nov 22 '18 at 15:59











  • Tried on Windows, doesn't lock the interface but warning still exists.

    – Engel
    Nov 22 '18 at 16:33













  • @Engel: the issue was detected and I re-edit the answer, please take a try, I tested the solution on Windows and Linux and it works.

    – tunglt
    Nov 22 '18 at 16:46











  • @Thung Le Thanh I'd tried and didn't work, because this: connect(webSocket, &QWebSocket::connected, this, [=](){ emit cxnEstablished(); }); I can't emit the signal, I'm going to try other approach but is seams to be close.

    – Engel
    Nov 22 '18 at 17:11













  • Your solution fix the problem but not the entire problem, because now ConnectionHelper can't emit any signal without having the warning :'(

    – Engel
    Nov 22 '18 at 17:26











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53433554%2fqt-qwebsocketopen-blocks-user-interface%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














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())
);
}





share|improve this answer
























  • I'm happy that you have found the solution. I posted also mine that I've used for the test.

    – tunglt
    Nov 22 '18 at 21:31











  • It's nice to see webSocket can move to another thread that way.

    – tunglt
    Nov 22 '18 at 21:42











  • I think found the source of the problem, the code now can work without tricks.

    – tunglt
    Nov 23 '18 at 9:45
















1














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())
);
}





share|improve this answer
























  • I'm happy that you have found the solution. I posted also mine that I've used for the test.

    – tunglt
    Nov 22 '18 at 21:31











  • It's nice to see webSocket can move to another thread that way.

    – tunglt
    Nov 22 '18 at 21:42











  • I think found the source of the problem, the code now can work without tricks.

    – tunglt
    Nov 23 '18 at 9:45














1












1








1







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())
);
}





share|improve this answer













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())
);
}






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 22 '18 at 21:21









EngelEngel

2118




2118













  • I'm happy that you have found the solution. I posted also mine that I've used for the test.

    – tunglt
    Nov 22 '18 at 21:31











  • It's nice to see webSocket can move to another thread that way.

    – tunglt
    Nov 22 '18 at 21:42











  • I think found the source of the problem, the code now can work without tricks.

    – tunglt
    Nov 23 '18 at 9:45



















  • I'm happy that you have found the solution. I posted also mine that I've used for the test.

    – tunglt
    Nov 22 '18 at 21:31











  • It's nice to see webSocket can move to another thread that way.

    – tunglt
    Nov 22 '18 at 21:42











  • I think found the source of the problem, the code now can work without tricks.

    – tunglt
    Nov 23 '18 at 9:45

















I'm happy that you have found the solution. I posted also mine that I've used for the test.

– tunglt
Nov 22 '18 at 21:31





I'm happy that you have found the solution. I posted also mine that I've used for the test.

– tunglt
Nov 22 '18 at 21:31













It's nice to see webSocket can move to another thread that way.

– tunglt
Nov 22 '18 at 21:42





It's nice to see webSocket can move to another thread that way.

– tunglt
Nov 22 '18 at 21:42













I think found the source of the problem, the code now can work without tricks.

– tunglt
Nov 23 '18 at 9:45





I think found the source of the problem, the code now can work without tricks.

– tunglt
Nov 23 '18 at 9:45













0














The error :




QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread




occurred while you try to call a network function directly from another thread (helper and its webSocket were in the other thread). Use invokeMethod or signal/slot instead.



EDIT 1 : in fact, the webSocket was created while ConnectionHelper constructor was called, and its belong to the main thread. The moveToThread does not allow the webSocket to be moved if ConnectionHelper was not set as its parent. To avoid that, the webSocket must be initialized with ConnectionHelper as a parent or when the thread was already started.



NOTE: if your application quits just after the dialog accepted() was fired (main window closed), you cannot see your signals emited.



UPDATE 2



    ConnectionHelper::ConnectionHelper(QObject *parent) : QObject(parent)
{
webSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);

connect( webSocket, &QWebSocket::stateChanged, this, [=](QAbstractSocket::SocketState s){
qDebug() << "Socket state changed : " << s;
} );
connect( webSocket, &QWebSocket::connected, this, [=](){
emit cxnOk();
webSocket->sendTextMessage("HELLO");
} );

void (QWebSocket::*error_signal)(QAbstractSocket::SocketError err) = &QWebSocket::error;

connect( webSocket, error_signal, this, [=](QAbstractSocket::SocketError err){
qDebug() << "On socket error : " << err;
} );

connect( webSocket, &QWebSocket::textMessageReceived, this, [=](QString s){
qDebug() << "text message received: " << s;
} );
}

void ConnectionHelper::setUrl(QUrl url)
{
if( webSocket->state() == QAbstractSocket::ConnectedState ){
webSocket->close();
}

qDebug() << "Open URL: " << url;
webSocket->open( url );
}


Initialization of ConnectionHelper instance :



    QThread * pThread = new QThread();
m_pHelper = new ConnectionHelper();

connect( m_pHelper, &ConnectionHelper::cxnOk, this, &MainWindow::onConnectionConnected, Qt::QueuedConnection );

m_pHelper->moveToThread( pThread );
pThread->start();


Change setUrl to slot then use invokeMethod to send the command to the helper instance.



    void MainWindow::on_pushButton_clicked()
{
QString ws = "ws://echo.websocket.org";
QMetaObject::invokeMethod( m_pHelper, "setUrl", Qt::QueuedConnection, Q_ARG( QUrl, QUrl(ws) ) );
qDebug() << "Invoke setUrl ended" ;

}

void MainWindow::onConnectionConnected()
{
qDebug() << "[MainWindow] On connection connected !!!!";
}


RESULTS:



    Invoke setUrl ended
Open URL: QUrl("ws://echo.websocket.org")
Socket state changed : QAbstractSocket::ConnectingState
Socket state changed : QAbstractSocket::ConnectedState
[MainWindow] On connection connected !!!!
text message received: "HELLO"





share|improve this answer


























  • I did it but still having the same warning QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    – Engel
    Nov 22 '18 at 15:59











  • Tried on Windows, doesn't lock the interface but warning still exists.

    – Engel
    Nov 22 '18 at 16:33













  • @Engel: the issue was detected and I re-edit the answer, please take a try, I tested the solution on Windows and Linux and it works.

    – tunglt
    Nov 22 '18 at 16:46











  • @Thung Le Thanh I'd tried and didn't work, because this: connect(webSocket, &QWebSocket::connected, this, [=](){ emit cxnEstablished(); }); I can't emit the signal, I'm going to try other approach but is seams to be close.

    – Engel
    Nov 22 '18 at 17:11













  • Your solution fix the problem but not the entire problem, because now ConnectionHelper can't emit any signal without having the warning :'(

    – Engel
    Nov 22 '18 at 17:26
















0














The error :




QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread




occurred while you try to call a network function directly from another thread (helper and its webSocket were in the other thread). Use invokeMethod or signal/slot instead.



EDIT 1 : in fact, the webSocket was created while ConnectionHelper constructor was called, and its belong to the main thread. The moveToThread does not allow the webSocket to be moved if ConnectionHelper was not set as its parent. To avoid that, the webSocket must be initialized with ConnectionHelper as a parent or when the thread was already started.



NOTE: if your application quits just after the dialog accepted() was fired (main window closed), you cannot see your signals emited.



UPDATE 2



    ConnectionHelper::ConnectionHelper(QObject *parent) : QObject(parent)
{
webSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);

connect( webSocket, &QWebSocket::stateChanged, this, [=](QAbstractSocket::SocketState s){
qDebug() << "Socket state changed : " << s;
} );
connect( webSocket, &QWebSocket::connected, this, [=](){
emit cxnOk();
webSocket->sendTextMessage("HELLO");
} );

void (QWebSocket::*error_signal)(QAbstractSocket::SocketError err) = &QWebSocket::error;

connect( webSocket, error_signal, this, [=](QAbstractSocket::SocketError err){
qDebug() << "On socket error : " << err;
} );

connect( webSocket, &QWebSocket::textMessageReceived, this, [=](QString s){
qDebug() << "text message received: " << s;
} );
}

void ConnectionHelper::setUrl(QUrl url)
{
if( webSocket->state() == QAbstractSocket::ConnectedState ){
webSocket->close();
}

qDebug() << "Open URL: " << url;
webSocket->open( url );
}


Initialization of ConnectionHelper instance :



    QThread * pThread = new QThread();
m_pHelper = new ConnectionHelper();

connect( m_pHelper, &ConnectionHelper::cxnOk, this, &MainWindow::onConnectionConnected, Qt::QueuedConnection );

m_pHelper->moveToThread( pThread );
pThread->start();


Change setUrl to slot then use invokeMethod to send the command to the helper instance.



    void MainWindow::on_pushButton_clicked()
{
QString ws = "ws://echo.websocket.org";
QMetaObject::invokeMethod( m_pHelper, "setUrl", Qt::QueuedConnection, Q_ARG( QUrl, QUrl(ws) ) );
qDebug() << "Invoke setUrl ended" ;

}

void MainWindow::onConnectionConnected()
{
qDebug() << "[MainWindow] On connection connected !!!!";
}


RESULTS:



    Invoke setUrl ended
Open URL: QUrl("ws://echo.websocket.org")
Socket state changed : QAbstractSocket::ConnectingState
Socket state changed : QAbstractSocket::ConnectedState
[MainWindow] On connection connected !!!!
text message received: "HELLO"





share|improve this answer


























  • I did it but still having the same warning QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    – Engel
    Nov 22 '18 at 15:59











  • Tried on Windows, doesn't lock the interface but warning still exists.

    – Engel
    Nov 22 '18 at 16:33













  • @Engel: the issue was detected and I re-edit the answer, please take a try, I tested the solution on Windows and Linux and it works.

    – tunglt
    Nov 22 '18 at 16:46











  • @Thung Le Thanh I'd tried and didn't work, because this: connect(webSocket, &QWebSocket::connected, this, [=](){ emit cxnEstablished(); }); I can't emit the signal, I'm going to try other approach but is seams to be close.

    – Engel
    Nov 22 '18 at 17:11













  • Your solution fix the problem but not the entire problem, because now ConnectionHelper can't emit any signal without having the warning :'(

    – Engel
    Nov 22 '18 at 17:26














0












0








0







The error :




QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread




occurred while you try to call a network function directly from another thread (helper and its webSocket were in the other thread). Use invokeMethod or signal/slot instead.



EDIT 1 : in fact, the webSocket was created while ConnectionHelper constructor was called, and its belong to the main thread. The moveToThread does not allow the webSocket to be moved if ConnectionHelper was not set as its parent. To avoid that, the webSocket must be initialized with ConnectionHelper as a parent or when the thread was already started.



NOTE: if your application quits just after the dialog accepted() was fired (main window closed), you cannot see your signals emited.



UPDATE 2



    ConnectionHelper::ConnectionHelper(QObject *parent) : QObject(parent)
{
webSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);

connect( webSocket, &QWebSocket::stateChanged, this, [=](QAbstractSocket::SocketState s){
qDebug() << "Socket state changed : " << s;
} );
connect( webSocket, &QWebSocket::connected, this, [=](){
emit cxnOk();
webSocket->sendTextMessage("HELLO");
} );

void (QWebSocket::*error_signal)(QAbstractSocket::SocketError err) = &QWebSocket::error;

connect( webSocket, error_signal, this, [=](QAbstractSocket::SocketError err){
qDebug() << "On socket error : " << err;
} );

connect( webSocket, &QWebSocket::textMessageReceived, this, [=](QString s){
qDebug() << "text message received: " << s;
} );
}

void ConnectionHelper::setUrl(QUrl url)
{
if( webSocket->state() == QAbstractSocket::ConnectedState ){
webSocket->close();
}

qDebug() << "Open URL: " << url;
webSocket->open( url );
}


Initialization of ConnectionHelper instance :



    QThread * pThread = new QThread();
m_pHelper = new ConnectionHelper();

connect( m_pHelper, &ConnectionHelper::cxnOk, this, &MainWindow::onConnectionConnected, Qt::QueuedConnection );

m_pHelper->moveToThread( pThread );
pThread->start();


Change setUrl to slot then use invokeMethod to send the command to the helper instance.



    void MainWindow::on_pushButton_clicked()
{
QString ws = "ws://echo.websocket.org";
QMetaObject::invokeMethod( m_pHelper, "setUrl", Qt::QueuedConnection, Q_ARG( QUrl, QUrl(ws) ) );
qDebug() << "Invoke setUrl ended" ;

}

void MainWindow::onConnectionConnected()
{
qDebug() << "[MainWindow] On connection connected !!!!";
}


RESULTS:



    Invoke setUrl ended
Open URL: QUrl("ws://echo.websocket.org")
Socket state changed : QAbstractSocket::ConnectingState
Socket state changed : QAbstractSocket::ConnectedState
[MainWindow] On connection connected !!!!
text message received: "HELLO"





share|improve this answer















The error :




QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread




occurred while you try to call a network function directly from another thread (helper and its webSocket were in the other thread). Use invokeMethod or signal/slot instead.



EDIT 1 : in fact, the webSocket was created while ConnectionHelper constructor was called, and its belong to the main thread. The moveToThread does not allow the webSocket to be moved if ConnectionHelper was not set as its parent. To avoid that, the webSocket must be initialized with ConnectionHelper as a parent or when the thread was already started.



NOTE: if your application quits just after the dialog accepted() was fired (main window closed), you cannot see your signals emited.



UPDATE 2



    ConnectionHelper::ConnectionHelper(QObject *parent) : QObject(parent)
{
webSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);

connect( webSocket, &QWebSocket::stateChanged, this, [=](QAbstractSocket::SocketState s){
qDebug() << "Socket state changed : " << s;
} );
connect( webSocket, &QWebSocket::connected, this, [=](){
emit cxnOk();
webSocket->sendTextMessage("HELLO");
} );

void (QWebSocket::*error_signal)(QAbstractSocket::SocketError err) = &QWebSocket::error;

connect( webSocket, error_signal, this, [=](QAbstractSocket::SocketError err){
qDebug() << "On socket error : " << err;
} );

connect( webSocket, &QWebSocket::textMessageReceived, this, [=](QString s){
qDebug() << "text message received: " << s;
} );
}

void ConnectionHelper::setUrl(QUrl url)
{
if( webSocket->state() == QAbstractSocket::ConnectedState ){
webSocket->close();
}

qDebug() << "Open URL: " << url;
webSocket->open( url );
}


Initialization of ConnectionHelper instance :



    QThread * pThread = new QThread();
m_pHelper = new ConnectionHelper();

connect( m_pHelper, &ConnectionHelper::cxnOk, this, &MainWindow::onConnectionConnected, Qt::QueuedConnection );

m_pHelper->moveToThread( pThread );
pThread->start();


Change setUrl to slot then use invokeMethod to send the command to the helper instance.



    void MainWindow::on_pushButton_clicked()
{
QString ws = "ws://echo.websocket.org";
QMetaObject::invokeMethod( m_pHelper, "setUrl", Qt::QueuedConnection, Q_ARG( QUrl, QUrl(ws) ) );
qDebug() << "Invoke setUrl ended" ;

}

void MainWindow::onConnectionConnected()
{
qDebug() << "[MainWindow] On connection connected !!!!";
}


RESULTS:



    Invoke setUrl ended
Open URL: QUrl("ws://echo.websocket.org")
Socket state changed : QAbstractSocket::ConnectingState
Socket state changed : QAbstractSocket::ConnectedState
[MainWindow] On connection connected !!!!
text message received: "HELLO"






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 23 '18 at 9:15

























answered Nov 22 '18 at 15:22









tunglttunglt

694210




694210













  • I did it but still having the same warning QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    – Engel
    Nov 22 '18 at 15:59











  • Tried on Windows, doesn't lock the interface but warning still exists.

    – Engel
    Nov 22 '18 at 16:33













  • @Engel: the issue was detected and I re-edit the answer, please take a try, I tested the solution on Windows and Linux and it works.

    – tunglt
    Nov 22 '18 at 16:46











  • @Thung Le Thanh I'd tried and didn't work, because this: connect(webSocket, &QWebSocket::connected, this, [=](){ emit cxnEstablished(); }); I can't emit the signal, I'm going to try other approach but is seams to be close.

    – Engel
    Nov 22 '18 at 17:11













  • Your solution fix the problem but not the entire problem, because now ConnectionHelper can't emit any signal without having the warning :'(

    – Engel
    Nov 22 '18 at 17:26



















  • I did it but still having the same warning QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    – Engel
    Nov 22 '18 at 15:59











  • Tried on Windows, doesn't lock the interface but warning still exists.

    – Engel
    Nov 22 '18 at 16:33













  • @Engel: the issue was detected and I re-edit the answer, please take a try, I tested the solution on Windows and Linux and it works.

    – tunglt
    Nov 22 '18 at 16:46











  • @Thung Le Thanh I'd tried and didn't work, because this: connect(webSocket, &QWebSocket::connected, this, [=](){ emit cxnEstablished(); }); I can't emit the signal, I'm going to try other approach but is seams to be close.

    – Engel
    Nov 22 '18 at 17:11













  • Your solution fix the problem but not the entire problem, because now ConnectionHelper can't emit any signal without having the warning :'(

    – Engel
    Nov 22 '18 at 17:26

















I did it but still having the same warning QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

– Engel
Nov 22 '18 at 15:59





I did it but still having the same warning QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

– Engel
Nov 22 '18 at 15:59













Tried on Windows, doesn't lock the interface but warning still exists.

– Engel
Nov 22 '18 at 16:33







Tried on Windows, doesn't lock the interface but warning still exists.

– Engel
Nov 22 '18 at 16:33















@Engel: the issue was detected and I re-edit the answer, please take a try, I tested the solution on Windows and Linux and it works.

– tunglt
Nov 22 '18 at 16:46





@Engel: the issue was detected and I re-edit the answer, please take a try, I tested the solution on Windows and Linux and it works.

– tunglt
Nov 22 '18 at 16:46













@Thung Le Thanh I'd tried and didn't work, because this: connect(webSocket, &QWebSocket::connected, this, [=](){ emit cxnEstablished(); }); I can't emit the signal, I'm going to try other approach but is seams to be close.

– Engel
Nov 22 '18 at 17:11







@Thung Le Thanh I'd tried and didn't work, because this: connect(webSocket, &QWebSocket::connected, this, [=](){ emit cxnEstablished(); }); I can't emit the signal, I'm going to try other approach but is seams to be close.

– Engel
Nov 22 '18 at 17:11















Your solution fix the problem but not the entire problem, because now ConnectionHelper can't emit any signal without having the warning :'(

– Engel
Nov 22 '18 at 17:26





Your solution fix the problem but not the entire problem, because now ConnectionHelper can't emit any signal without having the warning :'(

– Engel
Nov 22 '18 at 17:26


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53433554%2fqt-qwebsocketopen-blocks-user-interface%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Create new schema in PostgreSQL using DBeaver

Deepest pit of an array with Javascript: test on Codility

Costa Masnaga