QUdpSocket seems to stop receiving data from multicast group
-
I have a networked application where all the participants continously publish their status on a multicast address. Any participant then knows the status of all the other participants. But at some point a participant stops receiving anything on the QUdpSocket, but the others still receive status messages from that participant. It can take anyting from 15 minutes to 3 hours before this happens. I have made a sample console application that also has this problem. Compile and start at least two instances and wait for one of them to stop receiving anything. For convinience the application takes a name argument to separate connections from each others.
I´m running on Red Hat Enterprise 7.1 (64 bit) and I´m using Qt 5.5.0 an GCC 4.8.3.
Can anyone see a problem with this code?Connection.h -------------
#ifndef UDPCONNECTION_H #define UDPCONNECTION_H #include <QObject> #include <QUdpSocket> #include <QByteArray> #include <QTimer> class UdpConnection : public QObject { Q_OBJECT public: explicit UdpConnection( QString name, QObject* parent = 0); virtual ~UdpConnection(); void join(); void leave(); public slots: void sendDatagram(); void readPendingDatagrams(); private: Q_DISABLE_COPY( UdpConnection ) QString m_name; QHostAddress m_multicastAddress; int m_port; QUdpSocket m_socket; QByteArray m_content; QTimer m_sendTimer; }; #endif
Connection.cpp ---------------------------
#include "connection.h" #include <QDataStream> #include <QDateTime> #include <QDebug> UdpConnection::UdpConnection( QString name, QObject* parent ) : QObject( parent ), m_name( name ), m_multicastAddress( "224.4.4.10" ), m_port( 13589 ), m_socket( this), m_content(), m_send_timer( this ) { QString content = m_name; content.append( " - This is just some meaningless stuff to pass as data" ); QDataStream out( &m_content, QIODevice::WriteOnly ); out.setVersion( QDataStream::Qt_5_4 ); out << content; QObject::connect( &m_timer, &Qtimer::timeout, this, &UdpConnection::sendDatagram ); m_sendTimer.setInterval( 100 ); } UdpConnection::~UdpConnection() { leave(); } void UdpConnection::join() { if( !m_socket.bind( m_multicastAddress, (qint16)m_port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint ) ) { qDebug() << "Socket error reported: " << m_socket.errorString(); qDebug() << "Failed to bind to port, will not join."; return; } QObject::connect( &m_socket, &QUdpSocket::readyRead, this, &UdpConnection::readPendingDatagrams ); if( !m_socket.joinMulticastGroup( m_multicastAddress ) ) { qDebug() << "Failed to join, closing socket" ; m_socket.close(); return; } //setting ttl to zero to avoid traffic on network m_socket.setSocketOption( QAbstractSocket::MulticastTtlOption, QVariant(0) ); qDebug() << "Socket " << m_name << " has joined. " << QdateTime::currentDateTimeUtc().toString( Qt::ISODate ); m_sendTimer.start() } void UdpConnection::leave() { m_sendTimer.stop(); if( !m_socket.leaveMulticastGroup( m_multicastAddress ) ) { qDebug() << "Failed to leave group, disconnecting ready read signal."; QObject::disconnect( &m_socket, &QUdpSocket::readyRead, this, &UdpConnection::readPendingDatagrams ); return; } QObject::disconnect( &m_socket, &QUdpSocket::readyRead, this, &UdpConnection::readPendingDatagrams ); m_socket.close(); qDebug() << "Socket " << m_name << " closed."; } void UdpConnection::sendDatagram() { m_socket.writeDatagram( m_content, m_multicastAddress, (qint16)m_port ); } void UdpConnection::readPendingDatagrams() { while( m_socket.hasPendingDatagrams() ) { QByteArray datagram; datagram.resize( (int)m_socket.pendingDatagramSize() ); m_socket.readDatagram( datagram.data(), datagram.size() ); QDataStream in( &datagram, QIODevice::ReadOnly ); in.setVersion( QDataStream::Qt_5_4 ); QString content; in >> content; //print and discard content qDebug() << m_name << " received " << content << " " << QDateTime::currentDateTimeUtc().toString( Qt::ISODate ); } }
main.cpp ------------------------
#include <QCoreApplication> #include "connection.h" int main( int argc, char *argv[] ) { QCoreApplication a(argc, argv ); QString connectionName; if( qApp->arguments().count() <= 1 ) connectionName = "A"; else connectionName = qApp->arguments().at( 1 ); UdpConnection connection( connectionName ); connection.join(); { m_sendTimer.stop(); if( !m_socket.leaveMulticastGroup( m_multicastAddress ) ) { qDebug() << "Failed to leave group, disconnecting ready read signal."; QObject::disconnect( &m_socket, &QUdpSocket::readyRead, this, &UdpConnection::readPendingDatagrams ); return; } QObject::disconnect( &m_socket, &QUdpSocket::readyRead, this, &UdpConnection::readPendingDatagrams ); m_socket.close(); qDebug() << "Socket " << m_name << " closed."; } void UdpConnection::sendDatagram() { m_socket.writeDatagram( m_content, m_multicastAddress, (qint16)m_port ); } void UdpConnection::readPendingDatagrams() { while( m_socket.hasPendingDatagrams() ) { QByteArray datagram; datagram.resize( (int)m_socket.pendingDatagramSize() ); m_socket.readDatagram( datagram.data(), datagram.size() ); QDataStream in( &datagram, QIODevice::ReadOnly ); in.setVersion( QDataStream::Qt_5_4 ); QString content; in >> content; //print and discard content qDebug() << m_name << " received " << content << " " << QDateTime::currentDateTimeUtc().toString( Qt::ISODate ); return a.exec(); }
UdpConnection.pro ------------------------
QT += core network QT -= gui CONFIG += c++11 TARGET = UdpConnection CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp \ connection.cpp HEADERS += \ connection.h
[Added code tags ~kshegunov]
-
Hi,
It could be a timing problem or some overflow. With the latter I mean that the program processing the data may be slower than the program providing the data and at some point in time its buffer is full.
It would be interesting to know what the program is doing when it stops processing the Udp data. Have you attached an debugger to it in this situation and called "break" in the menu? Does the problem perhaps not appear in release version as e.g. the qDebug call takes its time?
-Michael. -
Hi,
It´s an interressting theory, but the test program, that just prints and discards data until there is no more data to read, has the same behaviour/error. See readPendingDatagrams() method. Also compiled and ran test program on RHEL 7.3 machine ( different HW and different network ) and it still has the same issue. In both cases I also checked with netstat -g to make sure the router did not drop a connection from the multicast group.
-marinas- -
Have you tried actually debugging as @m.sue suggested. After the problem manifests itself you can interrupt the program and add a breakpoint to see if any datagrams are received. I can't see anything wrong with it at a glance, but that's a doesn't mean there isn't a problem hidden somewhere.
-
@kshegunov
I have tried debugging it and the only thing happening is that the sendDatagram() method is still called every 100 ms as the timer times out. The other instance of the application still receives data from the instance that does not receive anything, not even the echo of its own data. -
@marinas said in QUdpSocket seems to stop receiving data from multicast group:
I have tried debugging it and the only thing happening is that the sendDatagram() method is still called every 100 ms as the timer times out.
But you don't get any incoming data through the
readyRead()
signal? That's rather strange. Perhaps you could try wireshark or another packet sniffer to see if packages are getting to the machine in question? -
@kshegunov Could you finally solve your problem? Because it seems that I am experiencing the same difficulty...
If you solved it how did you modify your UDP datagram receiver code? -
The original poster didn't follow up, and haven't posted a solution, sorry.