Qt QWebsocket :: open block пользовательский интерфейс

Я работаю над небольшой системой, она сделана несколькими клиентами и одним приложением администратора. У каждого клиента есть сервер QWebSocket для прослушивания запросов администратора, поэтому приложение администратора должно подключаться к разным клиентам.

Это мой диалог входа в систему:

Диалог входа

До входа в систему я не знаю, какой IP-адрес клиента, поэтому каждый раз, когда я отправляю учетные данные, мне нужно пытаться открыть соединение с этим IP-адресом. Проблема заключается в том, что в пользовательском интерфейсе Windows блокируется до тех пор, пока сервер сокетов не ответит или тайм-аут не достигнут, но в Windows он работает нормально.

РЕДАКТИРОВАТЬ 1: Я последовал за Тунг Ле Тхань предложения, поэтому код включает в себя его советы. Теперь главная проблема в том, что ConnectionHelper не может излучать сигнал, не получая QSocketNotifier: уведомители сокетов не могут быть включены или отключены из другого потока

у меня есть ConnectionHelper он отвечает за отправку полученных данных на и от установщика WebSocket.

main.cpp

ConnectionHelper *helper = new ConnectionHelper();
LoginDialog dialog(helper);

QThread* thread = new QThread();
helper->moveToThread(thread);
thread->start();

dialog.show();
return a.exec();

Конструктор LoginDialog:

connect(helper, &ConnectionHelper::onConnectionError, this, &LoginDialog::onCxnError);
connect(helper, &ConnectionHelper::loginInformationReceived, this, &LoginDialog::onLoginInfo);
connect(helper, &ConnectionHelper::cxnEstablished, this, &LoginDialog::onConnected);

Слот на принимается:

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

Я отключаю кнопку ОК, пока какой-либо ответ не будет получен и работает нормально в Linux, но в Windows весь блок пользовательского интерфейса и перестает отвечать до получения ответа.

Я тоже пытаюсь двигаться ConnectionHelper экземпляр в другой теме, но я получил этот ответ: QSocketNotifier: уведомители сокетов не могут быть включены или отключены из другого потока

У меня нет идей, мне нужно найти способ сделать webSocket->open(url) асинхронный или что-то в этом роде.

Благодарю.

0

Решение

Я понимаю что QWebSocket::open это единственная асинхронная функция, которую я использую. Так что мне нужно только иметь два потока, прежде чем установить URL и открыть соединение с сокетом.

После того, как Тунг Ле Тхань отвечает «и небольшая хитрость», теперь все работает отлично. Мое решение состояло в том, чтобы вернуться к стандартной угрозе, как только соединение будет установлено и начать излучать сигналы.

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

И сейчас LoginDialog необходимо отправить это Тема

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

Другие решения

Ошибка :

QSocketNotifier: уведомители сокетов не могут быть включены или отключены из другого потока

произошла, когда вы пытаетесь вызвать сетевую функцию непосредственно из другого потока (помощник и его webSocket находились в другом потоке). Вместо этого используйте invokeMethod или сигнал / слот.

РЕДАКТИРОВАТЬ 1: фактически webSocket был создан во время вызова конструктора ConnectionHelper, и он принадлежит основному потоку. MoveToThread не позволяет перемещать webSocket, если ConnectionHelper не был установлен в качестве его родителя. Чтобы избежать этого, webSocket должен быть инициализирован с ConnectionHelper в качестве родителя или когда поток уже был запущен.

НОТА: если ваше приложение завершает работу сразу после того, как было запущено диалоговое окно accept () (главное окно закрыто), вы не можете видеть испускаемые сигналы.

ОБНОВЛЕНИЕ 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 );
}

Инициализация экземпляра ConnectionHelper:

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

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

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

Измените setUrl на slot, затем используйте invokeMethod, чтобы отправить команду экземпляру помощника.

    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 !!!!";
}

РЕЗУЛЬТАТЫ:

    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"
0

По вопросам рекламы [email protected]