如何在非gui线程上正确创建QUdpSocket? Readyread未发出

时间:2017-04-05 07:10:28

标签: c++ multithreading qt sockets qudpsocket

我正在编写一个包装QUdpSocket

的网络库
QAbstractSocket *UdpNetworkStreamer::addConnection()
{
    QUdpSocket *udpSocket = new QUdpSocket(this);
    udpSocket->bind(connection.port, QUdpSocket::ShareAddress);
    bool ret = udpSocket->joinMulticastGroup(QHostAddress(connection.ip));
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::QueuedConnection);

    return udpSocket;
}
  1. 制作新的QUdpSocket
  2. 连接到readyRead信号。
  3. readDatagram被提出时致电readyRead
  4. 当我使用Qt GUI应用程序中的库时,一切正常。

    当另一个用户包含在Qt GUI应用程序之外使用的库时,问题就开始了。

    他调用addConnection(创建套接字并在readyRead上调用connect)

    调用addConnection的线程是非Qt。

    addConnection似乎已成功结束,但永远不会发出readyRead

    调用read(即使没有发出readyRead)会导致数据报读取成功。

    无效的修复:

    1. 将UDP套接字线程移动到this->线程

      QUdpSocket *udpSocket = new QUdpSocket();
      udpSocket->moveToThread(this->thread());
      udpSocket->setParent(this);
      
    2. 我尝试通过调用:void

      来模拟问题
      MainWindow::on__btnOpenMulticastReceiver_clicked()
      {
         QFuture<void> future = QtConcurrent::run(this, 
         &MainWindow::CreateMulticastConnection, testHandle);
      }
      

      这也导致了与用户对我的库相同的症状,这意味着readyRead未被发出。

    3. QSignalSpy - 我在readyRead信号上激活了间谍;虽然我可以直接从套接字读取数据,但计数器保持为零。当使用套接字在主线程上初始化时,间谍给出了有效的结果(即进展)。

    4. 我的问题:

      1. 我错过了什么,做错了什么?
      2. 即使没有在主GUI线程上创建readyRead发出$authenticated = Sentinel::getUser()->first_name; ,最简单的方法是什么 - 我找不到任何无GUI或外部Qt线程的样本。

2 个答案:

答案 0 :(得分:0)

我的猜测是你需要将Q_OBJECT宏添加到需要发出信号的类的开头。除非你这样做,否则信号槽机制将无法正常工作。

答案 1 :(得分:0)

我最终以这种方式解决问题:

void MainWindow::OpenConnection()
{
  QThread *t = new QThread();
  t->start();

  SocketWrapper *w= new SocketWrapper();

  w->moveToThread(t);

  w->metaObject()->invokeMethod(w, "CreateSocket", Qt::QueuedConnection);
}

在创建套接字时,必须使用套接字包装器invokeMethod()的线程调用movedTo(),以便创建套接字的线程将具有正在运行的事件循环。

除此之外,CreateSocket()必须是SocketWrapper中的一个插槽,类似于:

class SocketWrapper : public QObject
{
  Q_OBJECT
public:
  explicit SocketWrapper(QObject *parent = 0);


signals:

public slots:
  void readyRead();
  void CreateSocket();
private:
  QUdpSocket *_socket;
};