Всем привет, суть проблемы в названии (threadedfortuneserver - пример из дистрибутива Qt). В моей текущей реализации ответ клиенту приходит, но сервер сразу после этого падает. Отладчиком найти место падения не получается, т.к. оно происходит где-то в дизассемблированных кодах, в коих я ничего не понимаю.
Мой вариант thread.h:
class Thread : public QThread
{
Q_OBJECT
public:
Thread(int socketDescriptor, const QString &fortune, QObject *parent);
void run();
signals:
void error(QTcpSocket::SocketError socketError);
private:
int socketDescriptor;
QTcpSocket *tcpSocket;
QString text;
quint16 blockSize;
private slots:
void readClient();
};
Кусок server.cpp:
void Server::incomingConnection(qintptr socketDescriptor)
{
QString fortune = fortunes.at(qrand() % fortunes.size());
Thread *thread = new Thread(socketDescriptor, fortune, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
И гвоздь программы - thread.cpp:
void Thread::run()
{
tcpSocket = new QTcpSocket(NULL);
if (!tcpSocket->setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket->error());
return;
}
blockSize = 0;
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readClient()));
connect(tcpSocket, SIGNAL(disconnected()), tcpSocket, SLOT(deleteLater()));
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(quit()));
tcpSocket->waitForDisconnected();
}
void Thread::readClient()
{
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
return;
in >> blockSize;
}
if (tcpSocket->bytesAvailable() < blockSize)
return;
in >> text;
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << text;
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
tcpSocket->write(block);
tcpSocket->disconnectFromHost();
}
Ошибки из Application Output
QSocketNotifier: socket notifiers cannot be enabled from another thread
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x12ba6e40), parent's thread is Thread(0x12ba80e0), current thread is QThread(0x12b3e0b0)
QSocketNotifier: socket notifiers cannot be disabled from another thread
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 12b3e0b0. Receiver '' (of type 'QNativeSocketEngine') was created in thread 12ba80e0", file kernel\qcoreapplication.cpp, line 420
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
QNativeSocketEngine::waitForWrite() was called on an uninitialized socket device
Я понимаю, что эти ошибки связаны с наличием tcpSocket'a в классе треда. У меня своего рода дилемма: если убрать tcpSocket из класса треда, то сигнал readyRead() вызовется один раз, после чего тред просто повиснет и клиент не получит ответа, а если tcpSocket не убирать, приложение вообще падает с ASSERT FAILURE.
Подскажите пожалуйста, если есть идеи, как можно выбраться из такой ситуации.