Работа в сети без блокировки пользовательского интерфейса в Qt 4.7

У меня есть сервер, к которому могут подключаться несколько клиентов. Клиент - это графический интерфейс, а сервер - командная строка. У клиента есть несколько функций (например, подключение и вход в систему), которые при отправке на сервер должны получить ответ.

В основном мне нужно запустить функции QTcpSocket waitForConnection и waitForReadyRead. Однако мне нужно сделать это, не блокируя пользовательский интерфейс.

Я думал сделать следующее: иметь класс (клиент), реализующий QThread, который выполняет все ожидания. Это создается в main.

Client::Client (...)
{
    moveToThread (this); // Not too sure what this does
    mClient = new QTcpSocket (this);
    start();
}

void Client::run (void)
{
    exec();
}

void Client::connectToServer (...)
{
    mClient->connectToHost (hostname, port);
    bool status = mClient->waitForConnected (TIMEOUT);

    emit connected (status);
}

void Client::login (...)
{
    ... Similar to connectToServer ...
}

Затем графический интерфейс (например, ConnectToServerDialog), который я запускаю всякий раз, когда готов установить соединение. Я подключаю «подключенный сигнал» из потока к диалогу, поэтому, когда я подключен или время ожидания соединения истекло, он будет излучать этот сигнал.

QMetaObject::invokeMethod (mClient, "connectToServer", Qt::QueuedConnection,
    Q_ARG (const QString &, hostname), Q_ARG (quint16, port));

Я получаю ошибку утверждения с этим (не могу отправлять события объектам, принадлежащим другому потоку). Поскольку я довольно новичок в Qt, я не знаю, правильно ли я делаю.

Может ли кто-нибудь сказать мне, является ли то, что я делаю, хорошим подходом, и если да, то почему моя программа падает?


person Dave    schedule 28.11.2010    source источник
comment
labs.qt.nokia.com/2010/06 /17/ты делаешь неправильно   -  person smerlin    schedule 29.11.2010
comment
Да, я действительно нашел это и реализовал, большинство моих проблем было решено благодаря этой статье :-)   -  person Dave    schedule 29.11.2010


Ответы (2)


Я не рекомендую запускать поток в конструкторе.

Инициализируйте его так:

Client * client = new Client();
client->moveToThread(client);
client->start();

Или, если вы не хотите использовать такое решение, добавьте в конструктор перед start(); строкой this->moveToThread(this);

upd: извините, я не увидел в первый раз, что у вас есть эта строка.

person Vladimir Lagunov    schedule 28.11.2010
comment
-1 - Как указал Смерлин, это не способ сделать это правильно. - person zarzych; 29.11.2010

Лучше всего никогда не вызывать такие методы, как waitForBlah()... принуждение цикла событий к ожиданию неопределенного периода времени приводит к возможности зависания графического интерфейса в это время. Вместо этого подключите сигнал connect() вашего QTcpSocket к некоторому слоту, который соответствующим образом обновит ваш графический интерфейс, и пусть цикл обработки событий продолжится как обычно. Делайте свои подключенные вещи внутри этого слота.

person Jeremy Friesner    schedule 28.11.2010
comment
О, я знаю, но я хочу реализовать тайм-аут. Поэтому, если я не могу подключиться, скажем, в течение 4 секунд, я хочу, чтобы пользовательский интерфейс сказал: извините, не удалось подключиться... - person Dave; 29.11.2010
comment
Вы можете получить это, вызвав QTimer::singleShot(4000, this, SLOT(MyShowTimeoutErrorMessageSlot()))... блокировка не требуется. (обязательно установите флаг внутри вашего слота connect() и проверьте флаг внутри MyShowTimeoutErrorMessageSlot(), чтобы вы не получили сообщение «извините, не удалось подключиться» из вашего слота QTimer, если соединение было успешным до таймера уволенный!) - person Jeremy Friesner; 30.11.2010