我从Qt示例中修改了threaded fortune-server。 客户端连接到服务器,然后发送标头进行身份验证。
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()
。但是它总是返回false。 (来自文档:“重新实现此功能,为自定义设备提供阻止API。默认实现不执行任何操作,并返回false。”)。
那么如何在Qt中实现具有多个客户端和多个读/写的客户端/服务器应用程序?我真的想要改进应用程序设计的建议,并解决我目前的两个问题。
答案 0 :(得分:2)
如果没有调用QThread::exec()
来启动该线程/运行函数中的事件循环,则不能在线程中使用插槽或套接字信号。
由于你的checkBytes
插槽属于QThread,因此线程不会执行(有关于QThreads here的详细文章)
最接近你想要的例子是Network Chat(特别是两个班级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,并且因为它没有父代,您也应该手动删除它。