无法写入 QRunnable 内的 QTcpSocket

Posted

技术标签:

【中文标题】无法写入 QRunnable 内的 QTcpSocket【英文标题】:Can not write to QTcpSocket inside QRunnable 【发布时间】:2018-01-18 21:34:33 【问题描述】:

我在Qt 中构建了一个服务器,它接收每个连接到它的客户端并将连接发送到工作线程(我用QRunnable 实现了这一点,并将线程连接到QThreadPool)。

在我的线程中,我从套接字 (QTcpSocket socket) 读取没有问题,但是当我尝试写入它时,我收到以下错误:

QObject:不能为不同的父级创建子级 线。父线程是QThread(0x28602f90860)

我尝试通过添加代码行来解决此问题:

socket->setParent(this);

在我的线程的构造函数中 - 但它没有帮助,我收到以下错误:

QObject:无法为不同线程中的父级创建子级。 (Parent是QNativeSocketEngine(0x1dab6331c60),parent的线程 是 QThread(0x1dab62eacf0),当前线程是 QThread(0x1dab632b140) QSocketNotifier:不能启用或禁用套接字通知 另一个线程

有谁知道这是什么问题或如何解决?

相关代码sn-ps的稀疏示例:

class myTask  : public QObject , public QRunnable, public parser

     Q_OBJECT

public:
    myTask(QTcpSocket *s)
    
        socket = s;
        socket->setParent(this);
        // if i do here socket->write("hello world"); it's work , but not in run()
    

signals:
    void Result(int num);

protected:
    void run()
    
        socket->write("hello world"); // i get here the error
    

private:
    QTcpSocket *socket;
;


/* the creation of the worknig thread and the tcp client creation */
void MyClient::readyRead()


     myTask * mtask = new myTask(socket);
     mtask->setAutoDelete(true);

     // connect result to our loacal result function
     connect(mtask, SIGNAL(Result(int)), this, SLOT(taskResults(int)), Qt::QueuedConnection);

     //start havy job
     QThreadPool::globalInstance()->start(mtask);


void MyClient::SetSocket(int descriptor)

    socket = new QTcpSocket(this);

    connect(socket, SIGNAL(connected()), this, SLOT(connected()));
    connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
    connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));


    socket->setSocketDescriptor(descriptor);
    qDebug() <<"[*] client connected";



class MyClient : public QObject

    Q_OBJECT
public:
    explicit MyClient(QObject *parent = nullptr);
    void SetSocket(int descriptor);

signals:


public slots:
    void connected();
    void disconnected();
    void readyRead();
    void taskResults(int num);

private:
    QTcpSocket *socket;
;

【问题讨论】:

当然,问题可能与其他问题有关,而不是 QRunnable,它只是关于产生非阻塞任务。当然,您可以在没有“任务”的情况下以非阻塞方式使用 QTcpSocket。我会从这个开始,去掉不必要的细节的例子通常会有所帮助。如果可行,那么问题出在 QRunnable 使用的方式not 与套接字有关。 如果你尝试从myTak constructor 发送它工作正常,只有从迷你我进入run() 我开始得到错误 什么是“繁重的工作”?作为@AlexanderVX,Qt 的网络模块是异步的,设计用于主线程,因此您不需要将任何网络 I/O 本身移动到另一个线程。此外,您不能将对象移动到其父对象不存在的线程中,也不应从套接字不存在的线程中调用套接字的 read()write() 函数。 heavy job 是从网络文件中获取的,对此进行一些操作并将它们写回客户端,我在单独的可运行中执行它,因为我想要一个真正的多线程并避免任何阻塞行为 -它应该是功能齐全的真实服务器。 @YOKO 我建议您首先阅读有关线程和 QObject 的 Qt 文档。这将帮助您了解在跨线程使用 QObject 时可以做什么和不可以做什么:doc.qt.io/qt-5/threads-qobject.html 【参考方案1】:

如果您查看 QTcpServer 文档,其中一条注释说:

注意:如果您想在另一个线程中将传入连接作为新的QTcpSocket 对象处理,您必须将socketDescriptor 传递给另一个线程并在那里创建QTcpSocket 对象并使用其setSocketDescriptor() 方法。

为此,incomingConnection() 上还有一条注释:

注意:返回的QTcpSocket对象不能被其他线程使用。如果你想使用来自另一个线程的传入连接,你需要override incomingConnection()

所以子类QTcpServer 类并实现一个incomingConnection() 获取套接字描述符 并发送到线程。

这里是线程QTcpServer 的example。

【讨论】:

以上是关于无法写入 QRunnable 内的 QTcpSocket的主要内容,如果未能解决你的问题,请参考以下文章

重用 QRunnable

多继承自 QObject 和 QRunnable 错误

C++/Qt - QThread 与 QRunnable

完成后将 QRunnable 连接到函数/方法

QObject::connect 在 QRunnable - 控制台

QRunnable 中的计时器