Forum: PC-Programmierung Multicast über WLAN empfangen


von Max G. (l0wside) Benutzerseite


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.

von max (Gast)


Lesenswert?

vielleicht aktiviert der treiber den promiscuous mode?

von Peter II (Gast)


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.

von Max G. (l0wside) Benutzerseite


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.

: Bearbeitet durch User
von temp (Gast)


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.

von Max G. (l0wside) Benutzerseite


Lesenswert?

Guter Hinweis, ich habe tatsächlich auch den VirtualBox-Adapter unter 
Windows 10. Ich werfe ihn mal runter, auf der schwachbrüstigen Kiste 
läuft VirtualBox sowieso nicht.
Seltsam ist es trotzdem, mit dem Falcon-Treiber geht es ja.

von temp (Gast)


Lesenswert?

Deaktivieren hat bei mir gereicht.

von Max G. (l0wside) Benutzerseite


Lesenswert?

Das hat bei mir tatsächlich auch geholfen. Verstehe das, wer will.

Vielen Dank für den Tipp!

Max

von Alex W. (a20q90)


Lesenswert?

Und was macht der Treiber jetzt? Deaktiviert er den VB-Adapter?

von Max G. (l0wside) Benutzerseite


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
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.