QUdpSocket and broadcast receiver
-
Hi, These lines of code
QUSServer= new QUdpSocket(this); QUSServer->bind(3702, QAbstractSocket::DontShareAddress | QAbstractSocket::ReuseAddressHint); connect(QUSServer, SIGNAL(readyRead()), this, SLOT(DiscoveringPendingDatagrams()));
should permit to receive broadcast udp packets.
The problem is that the lines of code work only in a Windows machine but non in a Linux machine.
In other words the signal readyRead() is fired only in Windows but not Linux.
Have you got experience with QUdpSocket object? -
I don't see why these options should disallow receiving broadcasts.
-
I had a same problem but, solved with following code.
Try this.QUdpSocket* socket = new QUdpSocket(); socket->bind(QHostAddress("255.255.255.255"), port);
-
I had a same problem but, solved with following code.
Try this.QUdpSocket* socket = new QUdpSocket(); socket->bind(QHostAddress("255.255.255.255"), port);
@SHLEE said in QUdpSocket and broadcast receiver:
socket->bind(QHostAddress("255.255.255.255"), port);
This looks strange to me, this is the broadcast IP, you should better use 0.0.0.0 which is any IP.
I guess the problem is not with the IP, I guess the UDP port is already in use.
-
@SHLEE said in QUdpSocket and broadcast receiver:
socket->bind(QHostAddress("255.255.255.255"), port);
This looks strange to me, this is the broadcast IP, you should better use 0.0.0.0 which is any IP.
I guess the problem is not with the IP, I guess the UDP port is already in use.
@artwaw @KroMignon It is strange to me too but, it is true that it works on linux device.
Qt version is 4.8. It is not lastest but I think it doesn't matter.
This is test source. I talked all my experience and it's up to you. Good luck.mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QList> QT_BEGIN_NAMESPACE class QUdpSocket; QT_END_NAMESPACE namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; QList<QUdpSocket*> m_sendSockets; QList<QUdpSocket*> m_recvSockets; private slots: void onPushButtonBroadcastClicked(); void onLocalIpSocketReadyToRead(); void onBroadcastIpSocketReadyToRead(); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QUdpSocket> #include <QHostAddress> #include <QNetworkInterface> const int sendPort = 10000; const int recvPort = 12345; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); connect(ui->pushButtonBroadcast, SIGNAL(clicked()), this, SLOT(onPushButtonBroadcastClicked())); QList<QHostAddress> addresses = QNetworkInterface::allAddresses(); QUdpSocket* socket = NULL; while (addresses.count() > 0) { QHostAddress address = addresses.takeFirst(); if (address.isNull()) { continue; } // sender socket = new QUdpSocket(this); if (socket->bind(address, sendPort)) { m_sendSockets << socket; } else { delete socket; continue; } // receiver socket = new QUdpSocket(this); if (socket->bind(address, recvPort)) { m_recvSockets << socket; connect(socket, SIGNAL(readyRead()), this, SLOT(onLocalIpSocketReadyToRead())); } else { delete socket; continue; } } socket = new QUdpSocket(this); if (socket->bind(QHostAddress("255.255.255.255"), recvPort)) { m_recvSockets << socket; connect(socket, SIGNAL(readyRead()), this, SLOT(onBroadcastIpSocketReadyToRead())); } else { delete socket; } } MainWindow::~MainWindow() { qDeleteAll(m_sendSockets); qDeleteAll(m_recvSockets); delete ui; } void MainWindow::onPushButtonBroadcastClicked() { QString msg = ui->lineEdit->text(); for (int i = 0; i < m_sendSockets.count(); i++) { QUdpSocket* socket = m_sendSockets.value(i); if (socket == NULL) { continue; } socket->writeDatagram(msg.toUtf8(), QHostAddress::Broadcast, recvPort); } } void MainWindow::onLocalIpSocketReadyToRead() { QUdpSocket* socket = qobject_cast<QUdpSocket*>(QObject::sender()); if (socket == NULL) { return; } while (socket->hasPendingDatagrams()) { QHostAddress hostAddress; quint16 hostPort; QByteArray data; data.resize(socket->pendingDatagramSize()); socket->readDatagram(data.data(), data.size(), &hostAddress, &hostPort); QString msg = QString("%1:%2 - %3").arg(hostAddress.toString()).arg(hostPort).arg(QString::fromUtf8(data.constData(), data.size())); ui->textEditLocalIp->append(msg); } } void MainWindow::onBroadcastIpSocketReadyToRead() { QUdpSocket* socket = qobject_cast<QUdpSocket*>(QObject::sender()); if (socket == NULL) { return; } while (socket->hasPendingDatagrams()) { QHostAddress hostAddress; quint16 hostPort; QByteArray data; data.resize(socket->pendingDatagramSize()); socket->readDatagram(data.data(), data.size(), &hostAddress, &hostPort); QString msg = QString("%1:%2 - %3").arg(hostAddress.toString()).arg(hostPort).arg(QString::fromUtf8(data.constData(), data.size())); ui->textEditBroadcastIp->append(msg); } }
-
After a while I have found the solution. There is a different behaviour or QUdpSocket->bind() function between Linux / Mac and Windows, related to AnyIPv4 attribute.
In order to discover each onvif devices in the network the right approach is:for (int count= 0; count< QNetworkInterface::allAddresses().count(); count++) { if (QNetworkInterface::allAddresses().at(count).protocol()== QAbstractSocket::IPv4Protocol && QNetworkInterface::allAddresses().at(count)!= QHostAddress(QHostAddress::LocalHost)) { QUdpSocket *pQUdpSocket= new QUdpSocket(this); pQUdpSocket->bind(QNetworkInterface::allAddresses().at(count), 3702, QAbstractSocket::DontShareAddress | QAbstractSocket::ReuseAddressHint); pQUdpSocket->joinMulticastGroup(QHostAddress("239.255.255.250")); connect(pQUdpSocket, SIGNAL(readyRead()), this, SLOT(DiscoveringPendingDatagrams())); QVQUdpSockets.append(pQUdpSocket); } }
These lines of code work and ere been tested on Windows, Linux and Mac.
-
After a while I have found the solution. There is a different behaviour or QUdpSocket->bind() function between Linux / Mac and Windows, related to AnyIPv4 attribute.
In order to discover each onvif devices in the network the right approach is:for (int count= 0; count< QNetworkInterface::allAddresses().count(); count++) { if (QNetworkInterface::allAddresses().at(count).protocol()== QAbstractSocket::IPv4Protocol && QNetworkInterface::allAddresses().at(count)!= QHostAddress(QHostAddress::LocalHost)) { QUdpSocket *pQUdpSocket= new QUdpSocket(this); pQUdpSocket->bind(QNetworkInterface::allAddresses().at(count), 3702, QAbstractSocket::DontShareAddress | QAbstractSocket::ReuseAddressHint); pQUdpSocket->joinMulticastGroup(QHostAddress("239.255.255.250")); connect(pQUdpSocket, SIGNAL(readyRead()), this, SLOT(DiscoveringPendingDatagrams())); QVQUdpSockets.append(pQUdpSocket); } }
These lines of code work and ere been tested on Windows, Linux and Mac.
@mrdebug said in QUdpSocket and broadcast receiver:
for (int count= 0; count< QNetworkInterface::allAddresses().count(); count++) { if (QNetworkInterface::allAddresses().at(count).protocol()== QAbstractSocket::IPv4Protocol && QNetworkInterface::allAddresses().at(count)!= QHostAddress(QHostAddress::LocalHost)) { QUdpSocket *pQUdpSocket= new QUdpSocket(this); pQUdpSocket->bind(QNetworkInterface::allAddresses().at(count), 3702, QAbstractSocket::DontShareAddress | QAbstractSocket::ReuseAddressHint); pQUdpSocket->joinMulticastGroup(QHostAddress("239.255.255.250")); connect(pQUdpSocket, SIGNAL(readyRead()), this, SLOT(DiscoveringPendingDatagrams())); QVQUdpSockets.append(pQUdpSocket); } }
This code don't looks very good to me :(
Please avoid multiple calling ofQNetworkInterface::allAddresses()
. This don't make sense, you always work with a new list instance!
I would prefer something like:for(const auto & interface : QNetworkInterface::allAddresses()) { if (interface.protocol() == QAbstractSocket::IPv4Protocol && interface != QHostAddress(QHostAddress::LocalHost)) { auto pQUdpSocket = new QUdpSocket(this); pQUdpSocket->bind(interface, 3702, QAbstractSocket::DontShareAddress | QAbstractSocket::ReuseAddressHint); pQUdpSocket->joinMulticastGroup(QHostAddress("239.255.255.250")); connect(pQUdpSocket, SIGNAL(readyRead()), this, SLOT(DiscoveringPendingDatagrams())); QVQUdpSockets.append(pQUdpSocket); } }