简体   繁体   English

如何在非GUI线程上正确创建QUdpSocket? 已读未发出

[英]How to properly create QUdpSocket on non-gui thread ? Readyread not emitted

I'm writing a network library that wraps the 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. create a new QUdpSocket . 创建一个新的QUdpSocket
  2. connect to its readyRead signal. 连接到其readyRead信号。
  3. call readDatagram when readyRead is raised. readDatagram readyRead时,调用readDatagram

All is working fine when I use the library from a Qt GUI application. 当我从Qt GUI应用程序使用库时,一切工作正常。

The problem starts when another user includes the library used outside of a Qt GUI application. 当另一个用户包括在Qt GUI应用程序外部使用的库时,问题开始。

He calls the addConnection (which creates the socket and calls connect on the readyRead ) 他调用addConnection (它创建套接字并在readyRead上调用connect)

The thread on which the addConnection is called is non-Qt. 调用addConnection的线程是非Qt。

The addConnection seems to end successfully but the readyRead is never emitted. addConnection似乎已成功结束,但从来没有发出readyRead

Calling read (even though no readyRead was emitted) leads to a successful datagram read. 调用读取(即使未发出readyRead )也会导致成功读取数据报。

Fixes that did not work : 无效的修复:

  1. moving the the UDP socket thread to the this->thread 将UDP套接字线程移动到this-> thread

     QUdpSocket *udpSocket = new QUdpSocket(); udpSocket->moveToThread(this->thread()); udpSocket->setParent(this); 
  2. I tried to simulate the problem by calling:void 我试图通过调用以下方法模拟该问题:

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

    This also led to same symptoms as the one the user had with my library, meaning the readyRead wasn't emitted. 这也导致了与用户使用我的库时出现的症状相同的现象,这意味着没有发出readyRead

  3. QSignalSpy - I've activated a spy on the readyRead signal; QSignalSpy我已经激活了readyRead信号上的间谍; the counter kept on being zero although I could read data directly from the socket. 尽管我可以直接从套接字读取数据,但计数器始终保持为零。 The spy gave valid results (ie progressed) when used the socket was initialized on the main thread. 当使用套接字在主线程上初始化时,间谍给出了有效的结果(即已执行)。

My Questions: 我的问题:

  1. What am I missing and doing wrong ? 我想念什么并且做错了什么?
  2. What is the simplest way of having the readyRead emitted even though it is not created on the main GUI thread - I couldn't find any sample that works with no GUI or outside Qt threads. 即使未在主GUI线程上创建readyRead ,最简单的方法是什么-我找不到任何没有GUI或外部Qt线程的示例。

My guess is that you need to add Q_OBJECT macro to the beginning of the class from where you need to emit the signal. 我的猜测是,您需要在需要从那里发出信号的类的开头添加Q_OBJECT宏。 Unless you do this, the signal-slot mechanism will not function properly. 除非您这样做,否则信号插槽机制将无法正常运行。

I ended up solving the problem this way : 我最终以这种方式解决了这个问题:

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

  SocketWrapper *w= new SocketWrapper();

  w->moveToThread(t);

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

You must call invokeMethod() with the thread the socket wrapper was movedTo() upon creation of the socket, so that the thread that creates the socket will have a running event loop. 必须在创建套接字时使用套接字包装程序被movedTo()到的线程调用invokeMethod() ,以便创建套接字的线程将具有运行中的事件循环。

In addition to that, the CreateSocket() needs to be a slot in the SocketWrapper , something like that : 除此之外, CreateSocket()必须是SocketWrapper一个插槽,类似这样:

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


signals:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM