Ich habe ein Verständnisproblem beim Einlesen von UDP-Multicast-Paketen
unter Windows 7 mit Mingw.
Beim Start meines Programms gibt es immer wieder "Startschwierigkeiten",
die ich mir nicht erklären kann. Nur das wiederholte Starten der Routine
search_udp() aus main() führt irgendwann zum Erfolg. Läuft die
Endlosschleife einmal, ist alles ok und die Ausgaben sind zu 100%
vergleichbar mit Wireshark.
Doch was führt zu diesen Startschwierigkeiten?
Ausprobiert habe ich es in zwei völlig unterschiedlichen
Netzwerkumgebungen, doch das beobachtete Verhalten ist sehr ähnlich.
Eine typische Ausgabe des Programms ist: 1 | syncing ................................ synced
| 2 | M-SEARCH * HTTP/1.1
| 3 | HOST: 239.255.255.250:1900
| 4 | MAN: "ssdp:discover"
| 5 | MX: 5
| 6 | ST: urn: (usw)
|
Das Programm soll zunächst nur alle UDP-Pakete an 239.255.255.250 auf
Port 1900 anzeigen. Wie gesagt, das Programm funktioniert soweit, nur
warum der Start so holperig ist und immer viele fehlerhafte
Startversuche hinter syncing mit "." angezeigt werden, ist mir absolut
unklar. Ich finde auch keine Informationen im Netz, aber wahrscheinlich
suche ich mit den falschen Begriffen.
Natürlich habe ich mit Wireshark geprüft, dass während der
Startschwierigkeiten auch Pakete gesendet werden, die angezeigt werden
sollten... 1 | #include <WinSock2.h>
| 2 | #include <WS2tcpip.h>
| 3 | #include <iostream>
| 4 |
| 5 | #define MAX_SYNC_TRIES 600
| 6 | #define SYNC_LENGTH_SEC 2
| 7 |
| 8 | int search_udp();
| 9 |
| 10 | int main()
| 11 | {
| 12 | int i, ret;
| 13 | printf("syncing .");
| 14 | fflush(stdout);
| 15 | for(i=0; i<MAX_SYNC_TRIES; i++) {
| 16 | ret=search_udp(); // try function
| 17 | if (ret==0)
| 18 | i=MAX_SYNC_TRIES*2; // returned successful and ends loop
| 19 | else
| 20 | printf("."); // show next try
| 21 | fflush(stdout);
| 22 | }
| 23 | if (i<MAX_SYNC_TRIES*2)
| 24 | printf("\nERROR: no sync successful\n");
| 25 | return 0;
| 26 | }
| 27 |
| 28 |
| 29 | int search_udp()
| 30 | {
| 31 | WSAData wsaData;
| 32 | SOCKET sock;
| 33 | SOCKADDR_IN sockAddr;
| 34 | ip_mreq mreq;
| 35 | char buf[1555];
| 36 | unsigned long arg=0;
| 37 | WSAStartup(0x0202, &wsaData);
| 38 | sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
| 39 | if(sock == INVALID_SOCKET)
| 40 | printf("socket() error\n");
| 41 | sockAddr.sin_family = AF_INET;
| 42 | sockAddr.sin_addr.s_addr = INADDR_ANY;
| 43 | sockAddr.sin_port = htons(1900); // <============= multicast_port
| 44 | if(bind(sock, (sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
| 45 | printf("bind() error: %d\n", WSAGetLastError());
| 46 | mreq.imr_multiaddr.s_addr = inet_addr("239.255.255.250"); // <============= multicast_address
| 47 | mreq.imr_interface.s_addr = INADDR_ANY;
| 48 | if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) == SOCKET_ERROR)
| 49 | printf("setsockopt() error: %d\n", WSAGetLastError());
| 50 |
| 51 | // try SYNC_LENGTH_SEC seconds to get any answer
| 52 | time_t timetotry = time(NULL)+SYNC_LENGTH_SEC;
| 53 | while(arg==0){
| 54 | if(ioctlsocket ( sock, FIONREAD, &arg) == SOCKET_ERROR)
| 55 | printf("ioctlsocket() error\n");
| 56 | if (time(NULL)>=timetotry) {
| 57 | closesocket(sock);
| 58 | WSACleanup ();
| 59 | return 1; // not successful synced
| 60 | }
| 61 | }
| 62 | printf(" synced\n", arg);
| 63 | fflush(stdout);
| 64 |
| 65 | // now socket is synced
| 66 | while(1){ // endless
| 67 | memset(buf, 0, sizeof(buf));
| 68 | if(recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL) == SOCKET_ERROR)
| 69 | printf("recvfrom() error\n");
| 70 | if((buf[0] == 'M') || (buf[0] == 'N')) {// only M-SEARCH and NOTIFY
| 71 | printf("%s\n", buf);
| 72 | fflush(stdout);
| 73 | }
| 74 | }
| 75 | closesocket(sock);
| 76 | WSACleanup ();
| 77 | return 0;
| 78 | }
|
Dein Code wartet nur 2 Sekunden auf ein passendes Paket, aber diese
Pakete kommen nur so alle 30 Sekunden mal an. Passe mal die Wartezeit
auf >60 Sekunden an.
Vermutlich ist der Code aus einem Beispiel geklaut wo vorher eine
entsprechende Anfrage gesendet wurde.
Genau das habe ich anfangs auch gedacht! So habe ich angefangen.
Das entspricht etwa folgender Änderung im oberen Code: 1 | #define MAX_SYNC_TRIES 1
| 2 | #define SYNC_LENGTH_SEC 600
|
Leider bleibt dann ioctlsocket() ewig (mehr als 5 Minuten) konstant auf
0. Nur ganz selten (vielleicht einer von 20 Versuchen) klappt die
Erkennung der Pakete, dann aber kontinuierlich und ohne Probleme.
Daher die Änderung mit den mehreren Versuchen in einer Schleife.
Wie gesagt zeigt Wireshark während des ewigen Wartens viele passende
Pakete an.
> Vermutlich ist der Code aus einem Beispiel geklaut ...
"Geklaut" ist so ein böses Wort. Natürlich habe ich geschaut, wie andere
das Problem lösen. Nur so kann ich lernen. Oder gibt es eine bessere
Methode?
Noch eine Ergänzung:
> Nur ganz selten (vielleicht einer von 20 Versuchen) klappt die
> Erkennung der Pakete ...
Bei "Versuchen" ist der Neustart des Programms gemeint und nicht das
erneute Ausführen von search_udp() in der Schleife.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|