Unsolved Qt multicast works from Windows to Mac but not another around
-
I use an experimental project to test Qt multicast. It's acting like a simple chat program within a local network. I'm able to send messages from Windows to Mac, but not from Mac to Windows. Please see the comment in Multicast.cpp.
Both of them join a predefined group. I used some hard coded IP to find the corresponding interface to bind to. I have also checked the multicast groups on both platforms using netstat and netsh and it show the predefined group on both sides.
It's not a firewall issue, since I turned it off and the issue persisted.
Qt version:5.5
Any suggestion what I should do next to diagnose this issue?
netsh output:
C:\Users\Jerry>netsh interface ip show joins Interface 1: Loopback Pseudo-Interface 1 Scope References Last Address ---------- ---------- ---- --------------------------------- 0 1 Yes 224.0.0.251 0 4 Yes 239.255.255.250 Interface 4: Ethernet Scope References Last Address ---------- ---------- ---- --------------------------------- 0 0 Yes 224.0.0.1 0 2 Yes 224.0.0.251 0 1 Yes 224.0.0.252 0 0 Yes 239.255.43.21 0 4 Yes 239.255.255.250 Interface 8: Local Area Connection Scope References Last Address ---------- ---------- ---- --------------------------------- 0 0 Yes 224.0.0.1 0 2 Yes 224.0.0.251 0 1 Yes 224.0.0.252 0 4 Yes 239.255.255.250
netstat output
eve:~ Jerry$ netstat -g Link-layer Multicast Group Memberships Group Link-layer Address Netif 1:0:5e:7f:2b:15 <none> en0 1:0:5e:0:0:fb <none> en0 1:0:5e:0:0:1 <none> en0 33:33:ff:c9:32:14 <none> en0 33:33:0:0:0:fb <none> en0 33:33:ff:41:27:e <none> en0 33:33:0:0:0:1 <none> en0 33:33:ff:33:5b:7a <none> en0 1:80:c2:0:0:3 <none> en0 33:33:0:0:0:fb <none> en1 1:3:93:df:b:92 <none> en1 33:33:0:0:0:fb <none> awdl0 33:33:80:0:0:fb <none> awdl0 IPv4 Multicast Group Memberships Group Link-layer Address Netif 224.0.0.251 <none> lo0 224.0.0.1 <none> lo0 239.255.43.21 1:0:5e:7f:2b:15 en0 224.0.0.251 1:0:5e:0:0:fb en0 224.0.0.1 1:0:5e:0:0:1 en0 IPv6 Multicast Group Memberships Group Link-layer Address Netif ff02::fb%lo0 <none> lo0 ff02::2:ff33:9cc0%lo0 <none> lo0 ff01::1%lo0 <none> lo0 ff02::1%lo0 <none> lo0 ff02::1:ff00:1%lo0 <none> lo0 ff02::1:ffc9:3214%en0 33:33:ff:c9:32:14 en0 ff02::fb%en0 33:33:0:0:0:fb en0 ff01::1%en0 33:33:0:0:0:1 en0 ff02::2:ff41:270e%en0 33:33:ff:41:27:e en0 ff02::1%en0 33:33:0:0:0:1 en0 ff02::1:ff33:5b7a%en0 33:33:ff:33:5b:7a en0 ff02::fb%en1 33:33:0:0:0:fb en1 ff02::fb%awdl0 33:33:0:0:0:fb awdl0
Here is the source code
Multicast.h
#ifndef MULTICAST_H #define MULTICAST_H #include <QQuickItem> #include <QHostAddress> #include <QNetworkInterface> class QUdpSocket; class Multicast : public QQuickItem { Q_OBJECT public: Multicast(); Q_INVOKABLE void multicast(QString s); signals: void messageAdded(const QString msg); private slots: void processPendingDatagrams(); private: QNetworkInterface getNetworkInterfaceByAddress(QString adr); void printNetworkInterfaceInfo(QNetworkInterface ni); private: QHostAddress groupAddress; QUdpSocket *udpSocket; }; #endif // MULTICAST_H
Multicast.cpp
#include "multicast.h" #include <QtNetwork> Multicast::Multicast() { // hard coded group groupAddress = QHostAddress("239.255.43.21"); udpSocket = new QUdpSocket(this); udpSocket->bind(QHostAddress::AnyIPv4, 45454, QUdpSocket::ShareAddress); // hard coded IP to find network interface. 10.0.1.40 for the other devices // if I don't manually set this interface, and set loopback to 1, // this can receive the message from itself. Otherwise, it receives // nothing. udpSocket->setMulticastInterface(getNetworkInterfaceByAddress("10.0.1.39")); bool r = udpSocket->joinMulticastGroup(groupAddress); udpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption, QVariant(1)); QNetworkInterface intf(udpSocket->multicastInterface()); printNetworkInterfaceInfo(intf); connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams())); } QNetworkInterface Multicast::getNetworkInterfaceByAddress(QString adr) { QList<QNetworkInterface> il(QNetworkInterface::allInterfaces()); for (int i = 0; i < il.size(); i++) { QList<QNetworkAddressEntry> ade(il[i].addressEntries()); for (int j = 0; j < ade.size(); j++) { if (ade[j].ip().toString() == adr) return il[i]; } } return QNetworkInterface(); } void Multicast::printNetworkInterfaceInfo(QNetworkInterface ni) { qDebug() << ni.index() << ni.humanReadableName(); QList<QNetworkAddressEntry> ade(ni.addressEntries()); for (int j = 0; j < ade.size(); j++) qDebug() << ade[j].ip(); } void Multicast::multicast(QString msg) { QByteArray datagram = msg.toUtf8(); udpSocket->writeDatagram(datagram.data(), datagram.size(), groupAddress, 45454); } void Multicast::processPendingDatagrams() { while (udpSocket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); udpSocket->readDatagram(datagram.data(), datagram.size()); QString data(datagram); emit messageAdded(data); } }
main.cpp
#include <QApplication> #include <QQmlApplicationEngine> #include "multicast.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); qmlRegisterType<Multicast>("com.multicast.test", 1, 0, "Multicast"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
main.qml
import QtQuick 2.3 import QtQuick.Controls 1.2 import com.multicast.test 1.0 ApplicationWindow { id: applicationWindow1 visible: true width: 640 height: 480 title: qsTr("Hello World") Multicast { id : multicast } menuBar: MenuBar { Menu { title: qsTr("File") MenuItem { text: qsTr("&Open") onTriggered: console.log("Open action triggered"); } MenuItem { text: qsTr("Exit") onTriggered: Qt.quit(); } } } TextInput { id: textInput1 y: 57 width: 450 height: 20 text: qsTr("Text Input") anchors.left: parent.left anchors.leftMargin: 50 font.pixelSize: 12 } Button { id: button1 y: 57 text: qsTr("Button") anchors.left: textInput1.right anchors.leftMargin: 20 onClicked: { textEdit1.append(textInput1.text) multicast.multicast(textInput1.text) textInput1.text = "" } } TextEdit { id: textEdit1 y: 106 height: 327 readOnly: true anchors.left: parent.left anchors.leftMargin: 50 anchors.right: parent.right anchors.rightMargin: 50 font.pixelSize: 12 Connections { target: multicast onMessageAdded: { textEdit1.append(msg) } } } }
-
Using wireshark to monitor the traffic, the message from Mac dose arrive on Windows.
-
Just found on Windows the multicast group in bound to interface 4 Ethernet. But my program multicastInterface output 8 Local Area Connection.
Do I need 2 separate sockets for receiving and sendin individually?
-
The cause is the VirtualBox network card steals multicasting.This is a known issue in VirtualBox.
Disable the network interface or set a high Metic in settings solves the problem.
Now I need to find out if it's feasible to bind a socket on a specific interface.