Client-Struktur (sockaddr_in) wird erst beim 2. connect() korrekt gefüllt!?
-
Hallo!
Folgendes: Ich muss im Rahmen einer Vorlesung einen Monitor für WLAN's programmieren. Dabei überwacht ein der Servermonitor eine WLAN-Zelle. Die Clients in dieser Zelle sollen (wenn das Programm irgendwann fertig ist :)) dem Server in bestimmten Zeitintervallen Daten bzgl. ihrer Konfiguration schicken. Der Server "pflegt" diese Daten dann in eine MySql-DB ein, auf die dann der Netzwerkadmin von überall zugreifen kann. Soweit zur Projektbeschreibung.
Ich habe mir dazu erstmal eine Klasse "WMonServer" erstellt, die unter anderem die folgenden Methoden hat:
int WMonServer::readn(int fd, void *vptr, unsigned int n) { socklen_t len; int nleft; int nread; char *cptr; nleft = n; cptr = (char *)vptr; while (nleft > 0) { if ((nread = recvfrom(fd, cptr, nleft, 0, (struct sockaddr *)&cli_addr, &len)) < 0) { return (-1); } else if (nread == 0) // EOF { break; } // cout << "IP: " << inet_ntoa(cli_addr.sin_addr); nleft -= nread; cptr += nread; } return (n - nread); // should return 0 if all data has been send. }
Diese Methode ist ja nix Neues. Liest einfach Daten vom Socket. Erklärend sei angemerkt, dass "cli_addr" ein privates Attribut der Klasse ist.
Dazu gesellt sich in der Klasse die Methode "monitoring()", die ansich nichts Besonderes macht, außer die Methode "readn()" aufzurufen, und die erhaltenen Werte in die Datenbank einfügt:
void WMonServer::monitoring() { bool newClient = true; if (readn(sockfd, (struct LANDATA*)&mesg, MAXLINE) != 0) { cerr << "Fehler bei readn." << endl; exit(1); } // Copy the necessary data and a this client to the list. memcpy((struct in_addr *)&(cinfo.ip), (struct in_addr *) &(cli_addr.sin_addr), sizeof(struct in_addr)); memcpy((struct LANDATA *)&(cinfo.info), (struct LANDATA *)&mesg, sizeof(struct LANDATA)); for (unsigned int i = 0; i < clients.size(); i++) { if (clients[i].ip.s_addr == cli_addr.sin_addr.s_addr) // existiert schon ein Client mit der IP in dem Vector? newClient = false; } if (newClient) { clients.push_back(cinfo); *query << "INSERT INTO test (ip, vendor) VALUES (\"" << inet_ntoa(cinfo.ip) << "\"" << "\"" << cinfo.info.vendor << "\")"; query->execute(); cout << "Added " << inet_ntoa(cinfo.ip) << " to database." << endl; } else { cout << "Updated stats of " << inet_ntoa(cli_addr.sin_addr) << endl; *query << "UPDATE test SET vendor = \"VENDOR\" WHERE ip = \"" << inet_ntoa(cli_addr.sin_addr) << "\""; query->execute(); } }
Auf jeden Fall wird in der "main" nun ein Objekt der Klasse WMonServer erstellt und die Methode "monitoring()" aufgerufen. Vorher wurd der Socket natürlich entsprechend korrekt initialisiert.
Bis hierhin klappt auch alles ohne Probleme. Wenn ich nun aber das erste Mal mit einem Client connecte (im internen LAN), dann spuckt mir die Zeile "cout << "Added " << inet_ntoa(cinfo.ip) << " to database." << endl;" als IP-Adresse eine "0.0.0.0" vor. Unfreundlich, was?
Connecte ich ein zweites Mal ist plötzlich die richtige IP Adresse in der Struktur.
1. Frage: Kann sich jemand einen Reim darauf machen?
Es kommt noch besser:
Zu Debugging-Zwecken habe ich in der "readn()"-Methode nach dem recvfrom() einfach mal die IP-Adresse ausgeben lassen. (Auskommentierte Zeile). So, und sobald ich diese Ausgabe drinhab, also die Zeile einkommentiert habe, klappt es bereits beim ersten connect(). Wie bitte? o_O
2. Frage: Warum bewirkt das "cout", dass plötzlich kein zweiter connect() mehr nötig ist, um die Struktur richtig gefüllt zu bekommen?Ich wär euch echt dankbar wenn ihr mir Tipps geben könnt.
Vielen Dank im Voraus
Carsten
-
In readn wird socklen_t len nicht initialisiert.
-
Hmm, ich versteh dich glaube ich nicht ganz:
In Zeile 3 erstelle ich eine Variable "len" vom Typ "socklen_t":
socklen_t len;
Und dann in Zeile 13 übergebe ich als letzten Parameter die Adresse von "len".
Und diese Zeile ist doch dann auch für die Initialisierung zuständig!?
Bitte sag mir wenn ich da auf dem Holzweg bin. Wie gesagt, momentan kann ich mit deiner Lösung leider nichts anfangen. *schäm*[EDIT] Ahhhh, SChande über mein Haupt!
Ich hab total vergessen, dass da ja bereits die Größe drinstehen muss und dass nicht die Funktion recvfrom() dafür verantwortlich ist, diese Variable zu füllen. Vielen Dank!!!
Danke!