ソケットから読み取った 3 行を収集し、それらをソケットにエコーバックしようとする単純なスレッド TCP サーバーを作成しました。以下の関数 echoCommand がクラッシュします。
#include "fortunethread.h"
#include <QtNetwork>
#include <QDataStream>
FortuneThread::FortuneThread(int socketDescriptor, QObject *parent)
: QThread(parent), socketDescriptor(socketDescriptor), in(0)
{
}
void FortuneThread::run()
{
tcpSocketPtr = new QTcpSocket;
if (!tcpSocketPtr->setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocketPtr->error());
return;
}
in = new QDataStream(tcpSocketPtr);
connect(tcpSocketPtr, SIGNAL(readyRead()), this, SLOT(readCommand()) );
QThread::exec();
}
void FortuneThread::echoCommand()
{
QString block;
QTextStream out(&block, QIODevice::WriteOnly);
for (QStringList::Iterator it = commandList.begin(); it != commandList.end(); ++it) {
out << "Command: " << *it << endl;
}
out << endl;
tcpSocketPtr->write(block.toUtf8());
tcpSocketPtr->disconnectFromHost();
tcpSocketPtr->waitForDisconnected();
}
void FortuneThread::readCommand()
{
while (tcpSocketPtr->canReadLine())
{
commandList << (tcpSocketPtr->readLine()).trimmed();
}
if (commandList.size() > 2)
{
echoCommand();
}
}
スロット/シグナルを接続するファイルは次のとおりです。
#include "fortuneserver.h"
#include "fortunethread.h"
#include <stdlib.h>
FortuneServer::FortuneServer(QObject *parent)
: QTcpServer(parent)
{
}
void FortuneServer::incomingConnection(qintptr socketDescriptor)
{
QString fortune = fortunes.at(qrand() % fortunes.size());
FortuneThread *thread = new FortuneThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
ソケットの書き込み中または書き込み後に、次のエラーが発生します。
**QObject: Cannot create children for a parent that is in a different thread. (Parent is QNativeSocketEngine(0x7f19cc002720), parent's thread is FortuneThread(0x25411d0), current thread is QThread(0x220ff90)**
run() 関数で tcpSocketPtr を作成したので、この関数と同じスレッドにあることがわかります。ソケットの書き込みが失敗するのはなぜですか? telnetウィンドウに出力が表示されるので、書き込みは成功していることを指摘する必要があります...しかし、それでもソケットの書き込みは失敗します...
詳細情報...QThreadにスロットを入れるべきではないことがわかりました..これを回避する方法がわかりませんが、ここに私のクラス定義があります:
class FortuneThread : public QThread
{
Q_OBJECT
public:
FortuneThread(int socketDescriptor, QObject *parent);
void run();
signals:
void error(QTcpSocket::SocketError socketError);
private slots:
void readCommand();
private:
void echoCommand();
int socketDescriptor;
QDataStream *in;
QStringList commandList;
QTcpSocket *tcpSocketPtr;
};