Forum: PC-Programmierung C, Mingw, UDP-Pakete, Startschwierigkeiten


von Hardi S. (hardi13)


Lesenswert?

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
}

von Jim M. (turboj)


Lesenswert?

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.

von Hardi S. (hardi13)


Lesenswert?

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?

von Hardi S. (hardi13)


Lesenswert?

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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.