Qt QWebsocket::open blocks user interface
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.
c++ qt qtwebsockets
add a comment |
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.
c++ qt qtwebsockets
Hi there, not sure if this helps or not, but have you triedQCoreApplication::processEvents()
?
– TrebuchetMS
Nov 22 '18 at 15:18
Hi, you can capturethis
in lambda and useemit 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 suggestionQMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))
– Engel
Nov 22 '18 at 19:18
add a comment |
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.
c++ qt qtwebsockets
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.
c++ qt qtwebsockets
c++ qt qtwebsockets
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 triedQCoreApplication::processEvents()
?
– TrebuchetMS
Nov 22 '18 at 15:18
Hi, you can capturethis
in lambda and useemit 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 suggestionQMetaObject::invokeMethod( helper, "setUrl", Qt::QueuedConnection, Q_ARG(QUrl, QUrl(ws))
– Engel
Nov 22 '18 at 19:18
add a comment |
Hi there, not sure if this helps or not, but have you triedQCoreApplication::processEvents()
?
– TrebuchetMS
Nov 22 '18 at 15:18
Hi, you can capturethis
in lambda and useemit 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 suggestionQMetaObject::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
add a comment |
2 Answers
2
active
oldest
votes
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())
);
}
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
add a comment |
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"
I did it but still having the same warningQSocketNotifier: 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 nowConnectionHelper
can't emit any signal without having the warning :'(
– Engel
Nov 22 '18 at 17:26
|
show 2 more comments
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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())
);
}
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
add a comment |
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())
);
}
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
add a comment |
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())
);
}
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())
);
}
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
add a comment |
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
add a comment |
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"
I did it but still having the same warningQSocketNotifier: 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 nowConnectionHelper
can't emit any signal without having the warning :'(
– Engel
Nov 22 '18 at 17:26
|
show 2 more comments
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"
I did it but still having the same warningQSocketNotifier: 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 nowConnectionHelper
can't emit any signal without having the warning :'(
– Engel
Nov 22 '18 at 17:26
|
show 2 more comments
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"
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"
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 warningQSocketNotifier: 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 nowConnectionHelper
can't emit any signal without having the warning :'(
– Engel
Nov 22 '18 at 17:26
|
show 2 more comments
I did it but still having the same warningQSocketNotifier: 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 nowConnectionHelper
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
|
show 2 more comments
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 useemit 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