- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
免责声明:我对 Qt 和围绕线程和网络的任何类型的编程都比较陌生。我还采用了 Qt 示例、API 和其他在线示例中的大量代码。
所有代码都可以找到on GitHub .这段代码相对简单,因为它可以去掉 GUI。我认为以这种方式提供它与仅粘贴下面的代码相比也会有所帮助。
我想使用并且相信我需要使用线程,因为我需要多个客户端向服务器发送请求,服务器运行一些 SQL 代码,然后将结果吐回客户端(基本上派生一个 MySQL 服务器,但是具体到我在做什么)。不过现在,我只是在努力学习这一切的运作方式。
综上所述,如标题所述。我的客户端可以连接到服务器,服务器设置线程,并将通过 readReady 接收数据(字符串)。读入数据后,现在我只是试图将其回显给客户端。它会这样做,但只有一次。然后它吐出:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x266cca92ea0), parent's thread is serverThread(0x266cca9ed60), current thread is QThread(0x266cac772e0)
我无法向服务器发送任何进一步的数据,除非我让客户端重新连接,然后在发送数据后,它会完成它的工作,但随后会吐出同样的错误并停止运行。我尝试了很多不同的东西,但似乎无法解决问题。我什至尝试按照 API 中的建议为此设置一个 SIGNAL/SLOT:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
无论如何,我们将不胜感激!我的代码在下面..
// Project
#include "ServerDialog.h"
#include "ServerThread.h"
ServerThread::ServerThread(qintptr _socketDiscriptor, QObject *parent /*= 0*/)
: QThread(parent)
{
socketDiscriptor = _socketDiscriptor;
}
void ServerThread::run()
{
emit threadStarted(socketDiscriptor);
// Start Thread
clientSocket = new QTcpSocket;
// Set SocketDisc
if (!clientSocket->setSocketDescriptor(socketDiscriptor))
{
emit error(clientSocket->error());
return;
}
// Connect Socket and Signal
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
//// Loop Thread to Stay Alive for Signals and Slots
exec();
}
void ServerThread::readyRead()
{
QDataStream in(clientSocket);
in.setVersion(QDataStream::Qt_5_7);
in.startTransaction();
QString dataReceived;
in >> dataReceived;
if (!in.commitTransaction())
{
emit readyReadError(socketDiscriptor);
return;
}
emit readyReadMessage(socketDiscriptor, dataReceived);
echoData(dataReceived);
}
void ServerThread::disconnected()
{
emit threadStopped(socketDiscriptor);
clientSocket->disconnect();
clientSocket->deleteLater();
this->exit(0);
}
void ServerThread::echoData(QString &data)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
clientSocket->write(block);
}
因此在 ServerThread.cpp
中调用 echoData 时,即出现错误且 Socket 停止运行时。
我们将不胜感激任何帮助。我知道还有一些关于线程的“无法为...创建子项”的其他帖子。但我没有发现它们有任何帮助。我确实觉得有趣但不明白的一件事可能是使用 moveToThread(),但对此有很多不同的评论。
与仅通过解释或 API 指针相比,我通过代码示例和解释学得最好。谢谢!
最佳答案
大部分Qt网络函数都是异步的;他们不会阻塞调用线程。 如果您使用的是QTcpSocket
,则无需搞乱线程。事实上,为每个套接字创建一个线程是一种矫枉过正,因为该线程将把大部分时间花在等待某些网络操作完成上。下面是我将如何在 Qt 中实现单线程回显服务器:
#include <QtNetwork>
#include <QtCore>
//separate class for the protocol's implementation
class EchoSocket : public QTcpSocket{
Q_OBJECT
public:
explicit EchoSocket(QObject* parent=nullptr):QTcpSocket(parent){
connect(this, &EchoSocket::readyRead, this, &EchoSocket::EchoBack);
connect(this, &EchoSocket::disconnected, this, &EchoSocket::deleteLater);
}
~EchoSocket() = default;
Q_SLOT void EchoBack(){
QByteArray receivedByteArray= readAll();
write(receivedByteArray);
disconnectFromHost();
}
};
class EchoServer : public QTcpServer{
public:
explicit EchoServer(QObject* parent= nullptr):QTcpServer(parent){}
~EchoServer() = default;
//override incomingConnection() and nextPendingConnection()
//to make them deal with EchoSockets instead of QTcpSockets
void incomingConnection(qintptr socketDescriptor){
EchoSocket* socket= new EchoSocket(this);
socket->setSocketDescriptor(socketDescriptor);
addPendingConnection(qobject_cast<QTcpSocket*>(socket));
}
EchoSocket* nextPendingConnection(){
QTcpSocket* ts= QTcpServer::nextPendingConnection();
return qobject_cast<EchoSocket*>(ts);
}
};
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
EchoServer echoServer;
echoServer.listen(QHostAddress::Any, 9999);
QObject::connect(&echoServer, &EchoServer::newConnection, [&](){
EchoSocket* socket= echoServer.nextPendingConnection();
qDebug() << "Got new connection from: " << socket->peerAddress().toString();
});
return a.exec();
}
#include "main.moc"
EchoSocket
对象来处理它并向 qDebug()
打印一条语句,如果该事件正在接收先前创建的套接字上的某些东西,同一个线程将回显接收到的数据并关闭连接。 它永远不会阻塞在等待数据到达的单个连接上,也不会阻塞等待新连接到达。在本节中,我将解释为什么线程不适合您的工作方式:
您应该不在您的QThread
子类中声明插槽,而是使用worker QObject
并将它们移动到QThread
根据需要。
您在问题中提供的引述是您收到此警告的确切解释。您创建的 ServerThread
实例将存在于主线程(或创建它的任何线程)中。现在让我们从您的代码中考虑这一行:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
信号 readyRead()
将从当前 ServerThread
实例发出(因为 clientSocket
对象发射它存在于那里),然而,接收者对象是当前的 ServerThread
实例,但它存在于 main thread 中。这是documentation says :
If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
现在,Qt::QueuedConnection
的要点是在接收器对象的线程中执行插槽。这意味着,您的插槽 ServerThread::readyRead()
和 ServerThread::disconnected
将在主线程中执行。这很可能不是您想要的,因为您最终将从主线程访问 clientSocket
。之后,任何导致创建子 QObject
的 clientSocket
调用都会导致您收到警告(您可以看到 QTcpSocket::write()
做这个 here )。
关于c++ - QThread中的QTcpSocket将commitTransaction但是当调用Write时 "Cannot create children for a parent that is in a different thread.",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41083764/
我正在执行 UPDATE .WRITE() 语句,并发现它显然只有在您像这样定义它时才有效: string sql = "UPDATE [dbo].[Table] SET [Column].WRITE
我在 Unix 系统上用 C 编程。我知道: write(fd,"ABCD",4); 比这样做更好: write(fd, "A", 1); write(fd, "B", 1); write(fd, "
func hash(s string) uint32 { h := fnv.New32a() h.Write([]byte(s)) return h.Sum32() } 对于这
在经典的 asp 页面中,有人告诉我您可以使用 vbscript 或 jscript。而 jscript 就是 javascript。 所以我不确定 Response.Write、Response.W
当 openssl 子进程尝试 write() 到本地目录时,我收到此错误。在调用 write() 之前连接已关闭。它没有与 ssl 连接,因为我什至无法从 nodejs 文档启动示例代码。 我错过了
最近我在试验netty。我遇到了以下问题: ctx.channel().write(new TextWebSocketFrame("hello")) 没有在客户端返回 hello,但是 ctx.cha
请解释以下内容: def feed(data): import os print "DATA LEN: %s" % len(data) f = open("copy", "w") f.
有什么区别debug.write 和 Trace.write ?每个应该什么时候使用? 最佳答案 在典型的发布构建配置中,Debug class 被禁用并且什么都不做。 Trace但是,仍然可以在发行
我只是想知道,就性能而言,哪个更好(我在 FileStream 中使用 StreamWriter): 多次调用 Stream.Write(): StreamWriter sw = new Stream
我发现自己写给 stringwriter,然后在函数末尾执行 resp.Write(sw.ToString())。这是不必要的吗?如果我多次使用 HttpResponse.Write,即使我的页面是
我正在尝试通过 JavaScript 文件从 electron 打开一个新窗口,它可以工作,并打开了新窗口,但我无法将 HTML/文本写入新文件。我收到那个错误: Cannot read proper
我们对 QIODevice::write 的一般行为和具体的 QTcpSocket 实现感到非常困惑。有一个 similar question已经,但答案并不令人满意。主要的混淆源于分别提到的 byt
我知道这听起来像是一个愚蠢的问题: write(*,*) 和 write(6,*) ?我在我研究所的 super 计算机上运行一个复杂的代码,它通过一个不同于 6 的单元号输出一个数据文件,显然编译的
我有一个结构体,它可以通过一系列复杂的方法调用转换为文本,其中包含大量 write!调用。此文本可以写入文件或调试日志。我正在决定是否使用 fmt::Write 或 io::Write .我不能真正使
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
In the C standard library, an output can't be followed by an input and vice versa. 对于Linux API,可以在re
我希望能够为一件事做 document.write。然后延迟半秒,然后再记录。写一些。你知道这是否可能吗?而且,如果是这样,怎么办?到目前为止,我已经尝试过了,但没有奏效: document.writ
为什么通过 onclick 属性调用的 write() 函数解析为 document.write() 并替换文档?有什么办法可以阻止这种情况发生吗? Write Function Alternat
我想创建一个包含多个“页面”的文本文件,并将每个页面的字节偏移量记录在一个单独的文件中。为此,我将字符串打印到主输出文件并使用 bytes_written += file.write(str) 计算字
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 8 年前。 Improve this qu
我是一名优秀的程序员,十分优秀!