PDA

View Full Version : Qt multicast works from Windows to Mac but not another around



Jerry Hou
14th January 2016, 20:43
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::MulticastLoopback Option, 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(QNetworkInter face 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)
}
}
}
}

Added after 1 8 minutes:

Using wireshark to monitor the traffic, the message from Mac dose arrive on Windows.

Jerry Hou
14th January 2016, 23:42
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?

Added after 1 12 minutes:

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.