【问题标题】:Reading and writing QTcpSockets through different threads throws QSocketNotifier warning通过不同线程读写QTcpSockets抛出QSocketNotifier警告
【发布时间】:2021-02-10 15:59:55
【问题描述】:

基本上我想实现一个简单而基本的设计。我有一个客户端套接字,它向套接字服务器发送和读取设置。为了避免在主线程中阻塞,整个套接字处理应该在不同的线程中完成。所以我创建了类MySocket

MySocket.h(仅重要部分)

class MySocket : public QThread {
Q_OBJECT

public:

    int port;
    QHostAddress address;
    bool running;

    MySocket(QHostAddress addr, int port);

public slots:
    void sendMessage(QByteArray data);

protected:
    QTcpSocket* socket;    
    virtual void run();

signals:
    void onDataReady(const QByteArray &data);

private slots:
    void onReadyRead();
    void newConnection();
    void disconnected();
};

MySocket.cpp(仅重要部分)

#include "MySocket.h"

MySocket::MySocket(QHostAddress addr, int port) : port(port), address(addr), running(true)
{
}

void MySocket::onReadyRead()
{
    QByteArray datas = socket->readAll();
    //Send data to mainThread or somewhere else
    emit onDataReady(datas);
}

void MySocket::run()
{
    socket = new QTcpSocket();

    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
    QObject::connect(socket,SIGNAL(connected()),this,SLOT(newConnection()));
    QObject::connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
    socket->connectToHost(address, port);
    while(running)
    {
        QApplication::processEvents();
        QThread::msleep(10);
    }

}

void MySocket::sendMessage(QByteArray data){
    qDebug()<< "writing Data ...";
  
    if(socket->state() == QAbstractSocket::ConnectedState)
    {
       std::string message(data.constData(), data.length());
       qDebug() << "SendingData: " <<  QString::fromStdString(message);
       socket->write(data);
    }
    else{
        qDebug() << "Socket not ready for writing";
    }
}

主线程 (mainwindow.cpp) 只是创建并启动新线程。

mySocket = new MySocket(QHostAddress("127.0.0.1"), 3333);
controlSocket->start();

它还连接了用于写入的插槽和信号。

connect(this, SIGNAL(write(QByteArray)), mySocket, SLOT(sendMessage(QByteArray)));

每当我使用emit(write("some message")); 发出信号时,我都会收到以下错误/通知:

QSocketNotifier:不能从另一个线程启用或禁用套接字通知器

首先,我该如何解决这个问题?我创建了一个新线程,并且我还使用了许多其他面临类似问题的主题中提到的插槽/信号。套接字是否仍在发送这些消息?

【问题讨论】:

  • - 在 Qt 中,不需要将套接字放在线程中,因为一切都以非阻塞方式进行管理。 - 但是,如果您仍想这样做以平衡不同 CPU 上的负载,这是可能的。在这种情况下,我会在线程中读取数据并在读取数据时发出信号,以便与套接字相关的所有内容都在线程内。在您的连接中,“this”在主线程中! - 我认为你应该在线程中使用 QEventLoop 而不是 QApplication::processEvent。
  • @Alexandre:每当我想发送数据时都会收到警告(emit(write()) --> MySocket::sendMessage())。在这种情况下,“这个”真的是错误的吗?套接字实际上正在连接并调用 MySocket::newConnection。

标签: c++ multithreading qt sockets qt5


【解决方案1】:

MySocket 类的对象是一个 QThread,但是这个对象本身的实例存在于主线程中。 只有在 run() 函数中创建的对象存在于另一个线程中。所以你应该避免从主线程(即从 MySocket 类)访问“socket”。

2 个解决方案:

  • 最简单的方法是不使用线程。
  • 对于线程,我的建议是创建一个封装套接字(看起来很像 MySocket)的包装类,其中包含dataReceived(QByteArray) 的信号和sendData(QByteArray) 的插槽。然后,创建另一个扩展 QThread 的类,也具有相同的信号和槽,并在 run() 中本地创建包装类并将其信号和槽连接到扩展 QThread 的类的信号和槽,然后永远运行事件循环( QEventLoop::exec())。或者,您可以在包装类上使用标准 QThread 类(无需扩展)和方法 moveToThread()。这避免了创建扩展 QThread 的类的需要。

【讨论】:

  • 抱歉回复晚了,感谢您的回答。包装类需要继承形式 QObject 才能使用信号和槽。在处理程序(第二个新类)的 run() 中创建时,我必须提供一个父级。我可以像ControlSocketWrapper* socketWrapper = new ControlSocketWrapper(this); 一样使用它吗
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-24
  • 1970-01-01
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-23
相关资源
最近更新 更多