Multicast über WLAN empfangen

OP Persönliche Seite #4988416
Lesenswert?

Für eine Anwendung (auf Basis von KNXNet/IP) versuche ich, Multicast 
über WLAN zu empfangen. Aktuell verwende ich einen kommerziellen Treiber 
(Falcon), mit dem das auch prima funktioniert. Aus Lizenzgründen muss 
ich den aber durch eine eigene Lösung ersetzen.

Ich verwende Qt und habe das Beispiel 
http://doc.qt.io/qt-5/qtnetwork-multicastreceiver-example.html 
verwendet.

Mein Problem ist nun: die Multicast-Pakete kommen an, wenn der 
kommerzielle Treiber parallel aktiv ist. Ist er nicht aktiv, kommen sie 
nicht an. Auch im Wireshark sind sie nicht zu sehen.

Irgendwo fehlt hier eine Zutat zur Secret Sauce, aber welche? Was macht 
der kommerzielle Treiber anders? Google lieferte nur, dass man bind() 
und joinMulticastGroup() braucht, aber das ist ja drin. Die IP-Adresse 
ist natürlich angepasst. Der bind() geht auch auf das richtige 
Netzwerk-Interface, da habe ich den Code angepasst.

Max

Setup: Der Multicast-Sender hängt am Ethernet, Switch ist ein 
ungemanagter Netgear, Access Point ist ein Unifi.
Gast #4988426
Lesenswert?

WLAN und Multicast sind sehr speziell. Da alles Clients die Nachricht 
empfangen müssen, darf die Nachricht nur mit einer sehr geringen 
Bandbreite gesendet werden ( ich glaube sogar weniger als 11Mbit). Das 
wiederum führ bei vielen Nachrichten dafür das die "Luft" sehr voll ist. 
Also der Datendurchsatz sinkt extrem auch für anderen Teilnehmer

Es gibt einige AP die wandeln Multicast in Unicast um, um das Problem zu 
umgehen.
OP Persönliche Seite #4988433
Lesenswert?

@max: Das klingt plausibel. Allerdings irritiert mich, dass die Pakete 
im Wireshark auch nicht auftauchen - der müsste doch als erstes den 
promiscuous mode aktivieren, um überhaupt mitlesen zu können.

@Peter II: Bandbreite ist nicht das Thema, wir reden über einzelne 
Nachrichten von je 17 Byte Länge. Es werden auch nicht einzelne 
verschluckt, sondern es taucht gar nichts auf.
Gast #4988471
Lesenswert?

Mich hat ein Problem mit Multicasts unter W10 letzte Woche auch zur 
Weißglut gebracht. Verursacher war der Virtualbox-Host Only Netzwerk 
Adapter. Der wird meistens mit Installiert. Wenn man VMs im Bridge-Mode 
betreibt braucht man den aber nicht. Wohlgemerkt es geht nicht um 
Multicasts in VMs. Allein das Vorhandensein dieses Treibers verhinderte 
dass W10 Multicast-Packete empfangen konnte. Meine Tests dazu liefen 
unter nodejs. Ziel war das Absetzen von Multicast-Packeten von eiem 
ESP32 aus.
OP Persönliche Seite #4989243
Lesenswert?

Das manuelle Deaktivieren hat geholfen. Wobei das Deaktivieren nicht der 
Punkt war, es geht auch anders. Wichtig war, joinMulticastGroup() nicht 
auf dem VM-Adapter auszuführen.

KNXNet/IP-spezifisch: geplant ist, erst das Gateway zu suchen (dafür 
muss man der Multicast Group nicht beitreten, weil man es zwar per 
Multicast anspricht, die Antwort dann aber über direkt adressiertes UDP 
kommt). Auf den Interfaces, auf denen eine Antwort kam, wird dann 
Multicast aktiviert.

Die Lösung ist eher hässlich, aber wenn sie funktioniert...

Aktueller Code (noch ohne den geplanten Teil, sondern einfach WLAN hart 
eincodiert) anbei. Schönheit war kein Kriterium beim Schreiben.
main.cpp
1
#include "mainwindow.h"
2
#include <QApplication>
3
#include <QUdpSocket>
4
#include <QNetworkInterface>
5
#include <QList>
6
#include <QDebug>
7
#include <QThread>
8

9
int main(int argc, char *argv[])
10
{
11
    QApplication a(argc, argv);
12
    MainWindow w;
13

14
    QList<QNetworkInterface> mListIfaces = QNetworkInterface::allInterfaces();
15
    QHostAddress groupAddress = QHostAddress("224.0.23.12");
16

17
    for (QList<QNetworkInterface>::iterator iter_if = mListIfaces.begin(); iter_if != mListIfaces.end(); iter_if++) {
18
       qDebug() << "======" << iter_if->humanReadableName();// << (mListIfaces.at(i).flags() & QNetworkInterface::CanMulticast) << (mListIfaces.at(i).flags() & QNetworkInterface::IsLoopBack << mListIfaces.at(i).isValid()?"ja":"nein");
19
        if ((iter_if->flags() & QNetworkInterface::CanMulticast) == 0) {
20
            continue;
21
        }
22
        if ((iter_if->flags() & QNetworkInterface::IsLoopBack) > 0) {
23
            continue;
24
        }
25

26
        QList<QNetworkAddressEntry> ha_all = iter_if->addressEntries();
27
        for (QList<QNetworkAddressEntry>::iterator ha_iter = ha_all.begin(); ha_iter != ha_all.end(); ha_iter++) {
28
            if (ha_iter->ip().protocol() != QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) {
29
                continue;
30
            }
31
            qDebug() << ha_iter->ip().toString();
32

33
            QUdpSocket *sock_rx;
34
            sock_rx = new QUdpSocket();
35
            bool rez = sock_rx->bind(ha_iter->ip(), 3671, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
36

37
            qDebug() << "bind" << rez;
38
            if (!rez) {
39
                continue;
40
            }
41
            if (iter_if->humanReadableName() != "WLAN") {
42
                continue;
43
            }
44
            rez = sock_rx->joinMulticastGroup(groupAddress, *iter_if);
45
            QObject::connect(sock_rx,SIGNAL(channelReadyRead(int)),&w,SLOT(onUdpRx(int)));
46
            QUdpSocket *sock_tx = new QUdpSocket();
47
            sock_tx->bind(ha_iter->ip());
48
            QByteArray ss = QByteArrayLiteral("\x06\x10\x02\x01\x00\x0e\x08\x01");
49
            uint32_t ip = ha_iter->ip().toIPv4Address();
50
            ss.append((unsigned char)((ip >> 24) & 0xFF));
51
            ss.append((unsigned char)((ip >> 16) & 0xFF));
52
            ss.append((unsigned char)((ip >> 8) & 0xFF));
53
            ss.append((unsigned char)(ip & 0xFF));
54
            ss.append((uint8_t)((sock_rx->localPort() >> 8) & 0xFF));
55
            ss.append((uint8_t)((sock_rx->localPort()) & 0xFF));
56
            sock_tx->writeDatagram((const char*)ss.data(),ss.length(),QHostAddress("224.0.23.12"),3671);
57

58
            qDebug() << iter_if->humanReadableName() << rez << sock_rx->errorString();
59
        }
60
    }
61

62
    w.show();
63

64
    return a.exec();
65
}

mainwindow.h
1
#ifndef MAINWINDOW_H
2
#define MAINWINDOW_H
3

4
#include <QMainWindow>
5

6
namespace Ui {
7
class MainWindow;
8
}
9

10
class MainWindow : public QMainWindow
11
{
12
    Q_OBJECT
13

14
public:
15
    explicit MainWindow(QWidget *parent = 0);
16
    ~MainWindow();
17

18
public slots:
19
    void onUdpRx(int);
20

21
private:
22
    Ui::MainWindow *ui;
23
};
24

25

26
#endif // MAINWINDOW_H

mainwindow.cpp
1
#include "mainwindow.h"
2
#include "ui_mainwindow.h"
3
#include <QUdpSocket>
4
#include <QNetworkDatagram>
5

6

7
MainWindow::MainWindow(QWidget *parent) :
8
    QMainWindow(parent),
9
    ui(new Ui::MainWindow)
10
{
11
    ui->setupUi(this);
12

13
}
14

15
MainWindow::~MainWindow()
16
{
17
    delete ui;
18
}
19

20
void MainWindow::onUdpRx(int len) {
21
    printf("RX %i\n",len); fflush(stdout);
22
    QUdpSocket *sock = (QUdpSocket*)(QObject::sender());
23
    qDebug() << "avail" << sock->bytesAvailable() << sock->hasPendingDatagrams();
24
    QNetworkDatagram dg = sock->receiveDatagram();
25
    QByteArray data = dg.data().toHex();
26
    ui->bla->append(dg.senderAddress().toString()+":"+QString::number(dg.senderPort())+" ");
27
    ui->bla->append(dg.destinationAddress().toString()+":"+QString::number(dg.destinationPort())+" ");
28
    ui->bla->append(data);
29

30
    qDebug() << data;
31
    ui->bla->append("\n");
32
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren