Проблемы с чтением данных из QTcpSocket - PullRequest
0 голосов
/ 16 августа 2011

Я модифицировал многопоточный сервер удачи из примеров Qt. Клиент подключается к серверу, а затем отправляет заголовок для проверки подлинности.

tcpSocket = new QTcpSocket();
tcpSocket->connectToHost(addr, port);
QByteArray block = "someheader";
int x = tcpSocket->write(block);
qDebug() << x;

Здесь клиент выглядит нормально и qDebug печатает фактический размер block.

На стороне сервера я предварительно настроил incomingConnection, и я запускаю поток для каждого нового соединения.

void Server::incomingConnection(int socketDescriptor) {
    const QString &str = vec[qrand() % vec.size()];
    SpellThread *thread = new SpellThread(socketDescriptor, str);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    qDebug() << " -- incoming connection";
    thread->start();
}

Я подключаюсь sock, чтобы проверить, есть ли что почитать. (sock здесь QTcpServer*)

void SpellThread::run() {
    qDebug() << " -- in spellthread";
    connect(sock, SIGNAL(readyRead()), this, SLOT(checkBytes()));
    //....
    qDebug() << " -- end spellthread";
}

Первая проблема заключается в том, что при отправке данных с клиента readyRead не запускается. (Я добавил отладочное сообщение в checkBytes) Сообщения:

 -- incoming connection 
 -- in spellthread 
 -- end spellthread

Хотя клиент печатает фактический размер длины заголовка.

Вторая проблема в том, что checkBytes в настоящее время очень плохо спроектирован. Сначала он проверяет заголовок OK и устанавливает флаг, затем он получает размер сообщения и устанавливает другой флаг, и, наконец, он получает реальное сообщение. Это очень неуклюже. Сначала я попытался избежать сигналов и вместо этого использовал sock->waitForReadyRead(). Однако это всегда возвращает ложь. (Из документов: «Переопределите эту функцию, чтобы предоставить API блокировки для пользовательского устройства. Реализация по умолчанию ничего не делает и возвращает false.»).

Так как же реально сделать клиент-серверное приложение в Qt с несколькими клиентами и несколькими операциями чтения / записи? Мне очень нужны предложения по улучшению дизайна моего приложения и решению моих текущих двух проблем.

1 Ответ

2 голосов
/ 22 августа 2011

Нельзя использовать слоты или сигналы сокетов с потоком без вызова QThread::exec() для запуска цикла событий в этом потоке / функции запуска.

Поскольку ваш слот checkBytes принадлежит QThread, он не будет выполняться потоком (здесь есть подробная статья о QThreads )

Ближайший пример, который, кажется, уже делает то, что вам нужно, это Сетевой чат (особенно два класса Server и Connection).

----------
Редактировать
Если вам нужно использовать потоки (без какого-либо слота), объект QTcpSocket должен принадлежать тому же потоку, к которому вы вызываете waitForReadyRead. Например, с:

SpellThread::SpellThread(int socketDescriptor, const QString & str) {
    tcpSocket = new QTcpSocket(); // There should be no parent to be able
                                  // to move it to the thread
    tcpSocket->moveToThread(this);
    ...

Или путем создания объекта QTcpSocket внутри функции run, чтобы он автоматически принадлежал этому потоку (это было кратко объяснено в примере состояния). Если вы выделяете QTcpSocket динамически, и поскольку у него нет родителя, вы также должны удалить его вручную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...