Lösung Übung 2Das meisste ist schon da
Ausgehend von der ersten Übung müssen wir nur ein paar Zeilen Code ändern.
Da wir nun die ServerIP durch Eingabe einer Ip oder eines Hostnames in die Kommandozeile erhalten sollen, müssen wir die in netdb.h vorliegende function gethostbyname() benutzen.
Also müssen wir nur im Client (udpEchoTest.cpp) das initialisieren der Variablen ändern.
Alte Version
C++
const unsigned long SERVER_IP = inet_addr(argv[1]);
const int SERVER_PORT = atoi(argv[2]);
(..)
//Variablen Initialisieren
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = SERVER_IP;
Für die Modifizierung brauchen wir folgende Codestücke:
1.) #include <netdb.h>
2.) hostent* host_ptr;
3.) host_ptr = gethostbyname(argv[1]);
4.) server_addr.sin_addr = *((in_addr*)(host_ptr->h_addr));
und zusätzlich eine neue Exception die geworfen wird,
wenn in gethostbyname() ein Fehler auftritt und das Ergebnis (host_ptr) gleich NULL ist.
1. Der include ist notwendig um gehostbyname() verwenden zu können.
2. Das Ergebnis von gethostbyname() ist ein Pointer auf ein in_addr-Structure allerdings vom Typ hostent*, wir speichern das Ergebnis in host_ptr.
3. Auflösung des Hostnames aus argv[1], eine IP-Adresse kann die Function auch annehmen. Tritt ein Fehler auf, wird ein NULL-Pointer übergeben.
4. Hier kommt die erst wirkliche Änderung der Initialisierung aus Übung 1.
Statt der sin_addr.s_addr die IP zuzuweisen:
server_addr.sin_addr.s_addr = SERVER_IP;
können wir direkt an die sin_addr das Structure aus gethostbynamezuweisen, da der Typ aber hostent* ist, müssen wir dies Typecasten:
server_addr.sin_addr = *((in_addr*)(host_ptr->h_addr));
5. Eine entsprechende Exception muss erzeugt werden.
So sieht eine entsprechende Lösung für die zweite NWK-Labor-Übung wie folgt aus:
C++
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
using namespace std;
class RECVError{};
class BINDError{};
class SENDError{};
class SOCKETError{};
class HOSTError{};
class AufrufFehler{};
int main(int argc, char* argv[])
{
try
{
if(argc != 3)
throw AufrufFehler();
const int SERVER_PORT = atoi(argv[2]);
sockaddr_in server_addr; //Server Adresse
hostent* host_ptr;
int sfd;
int binding;
int sending;
int recv;
char buf_ptr[256];
char nachricht[256] = "TEST TEST"; //char variable für message
//Variablen Initialisieren
host_ptr = gethostbyname(argv[1]);
if(host_ptr == NULL)
throw HOSTError();
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr = *((in_addr*)(host_ptr->h_addr));
/* Ab jetzt kann der sfd und alles weitere wie in Aufgabe 2 erzeugt werden,
* ein entsprechender catch(HOSTError)
* ist noch einzubauen.
*/
}
}
Lösungsansatz aus 2010
Hier ist die Lösung zu Aufgabe 2 in NWK. Es ist jetzt möglich den Hostname oder eine IP anzugeben. Wird ein ungültiger Hostname oder eine ungültige IP kommt eine Exception.
CPP
// echo_client.cpp //
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
using namespace std;
class HILFE{};
class SFD{};
class REC{};
class SEND{};
class GETHOSTNAME{};
int main(int argc, char* const argv[])
{
// Initialisierung der Variablen
unsigned long ip; // enthaellt spaeter die ip
int port; // enthaellt spaeter den Port
int sfd; // Socket Descriptor: Fehlercode fuer socket(...)
int send; // Fehlercode fuer sendto(...)
int rec; // Fehlercode fuer recvfrom(....)
char nachricht[] = "Hallo Herr Exner"; // die zusendende Nachricht
char buffer[256]; // die empfangende Nachricht
struct hostent *hent; // Hostname
sockaddr_in server_addr; // Server Daten
try
{
// wirf eine Exception wenn nicht IP und Port angegeben werden
if(argc != 3)
throw HILFE();
// Ausgabe der Parameter
for(int c = 0; c < argc; c++)
{
cout << "argv[" << c << "] = " << argv[c] << endl;
}
// Port Ermittlung
port = atoi(argv[2]);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
hent = gethostbyname(argv[1]); // ermitteln der IP des Hostnames
// wenn keine gültige IP / Hostname verwendet wurde
if (hent == NULL)
throw GETHOSTNAME();
server_addr.sin_addr = *(struct in_addr*) hent->h_addr;
// Socket erstellen
sfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sfd < 0)
throw SFD();
// verschicken der Nachricht
send = sendto(sfd, nachricht, sizeof(nachricht), 0,(sockaddr*)&server_addr, (socklen_t)sizeof(server_addr));
if (send < 0)
throw SEND();
// Antwort empfangen
socklen_t size = sizeof(server_addr);
rec = recvfrom(sfd, buffer, sizeof(buffer), 0,(sockaddr*)&server_addr, &size);
if (rec < 0)
throw REC();
// Antwort ausgeben
cout << "IP des Servers: " << inet_ntoa(server_addr.sin_addr) << endl;
cout << "Antwort erhalten: " << buffer << endl;
// Socket schliessen
close(sfd);
}
// Ausgabe bei fehlerhafter Eingabe
catch(HILFE)
{
cout << "n usage: " << argv[0] << " IP PORT n";
}
catch(GETHOSTNAME)
{
cout << "error beim ermitteln der IP vom DNS NAMENn";
}
catch(SFD)
{
cout << "error beim Socketn";
}
catch(SEND)
{
cout << "error beim Empfangen der Nachrichtn";
}
catch(REC)
{
cout << "error beim Senden der Nachrichtn";
}
// Ausgabe bei sonstigen Fehlern
catch(...)
{
cout << "n error! n";
}
return 0;
}
|