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.
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.
@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
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.
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.
Das hat bei mir tatsächlich auch geholfen. Verstehe das, wer will. Vielen Dank für den Tipp! Max
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.