I'm writing a network library that wraps the 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;
}
QUdpSocket
.readyRead
signal.readDatagram
when readyRead
is raised.All is working fine when I use the library from a Qt GUI application.
The problem starts when another user includes the library used outside of a Qt GUI application.
He calls the addConnection
(which creates the socket and calls connect on the readyRead
)
The thread on which the addConnection
is called is non-Qt.
The addConnection
seems to end successfully but the readyRead
is never emitted.
Calling read (even though no readyRead
was emitted) leads to a successful datagram read.
Fixes that did not work :
moving the the UDP socket thread to the this->thread
QUdpSocket *udpSocket = new QUdpSocket();
udpSocket->moveToThread(this->thread());
udpSocket->setParent(this);
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.
QSignalSpy
- I've activated a spy on the readyRead
signal; the counter kept on being zero although I could read data directly from the socket. The spy gave valid results (i.e. progressed) when used the socket was initialized on the main thread.
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. 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.
In addition to that, the CreateSocket()
needs to be a slot in the SocketWrapper
, something like that :
class SocketWrapper : public QObject
{
Q_OBJECT
public:
explicit SocketWrapper(QObject *parent = 0);
signals:
public slots:
void readyRead();
void CreateSocket();
private:
QUdpSocket *_socket;
};