Socketprogrammierung
Linux
Datagram- Sockets
Aufgabe 1Datagram-Socket / SendTo /Receive
Entwickeln Sie für das Datensendeprogramm "Datagram/Sendto" ein Empfangsprogramm, welches die gesendeten Datagramme zur Anzeige bringt.Hinweis: Sender und Empfänger können auf einem Rechner gestartet werden.
Vorlagen
Sende-Programm: Datagram / Sendto
Vorlage für das Empfangsprogramm Datagram / Read
Fragen Fragen 1 zur Socketprogrammierung
Aufgabe 2Datagram-Socket / Time Protocol Testen Sie das folgende Programm, das mit Hilfe des Time Protocol (RFC 868) von einem UNIX- Rechner die Sekunden, die seit dem 1. Januar 1900 0.00 Uhr GMT verstrichen sind, erfragt und in eine Zeitangabe im Format Stunde: Minute: Sekunde anzeigt.
Modifizieren Sie das Programm so, dass beim Kompilieren keine Warnungen mehr erzeugt werden!
Fragen
VorlageSiehe Aufgabenblatt
timeprotocol muss mit einem Argument ( = Zielrechner ) gestartet werden!
Aufgabe 3Datagram-Socket / Broadcasts
a.)Ergänzen Sie das Sende-Programm (Vorlage) so, dass es in ein bestimmtes Subnetz seine Daten als Broadcast sendet.b.) Realisieren Sie ein Programm, welches die Daten des Sendprogramms empfängt und anzeigt.
Vorlagen
/***************************************************************************
DasProgramm Zyklische Broadcast sendet zyklisch ein Datenmuster (nachdem es ergänzt wurde)
Das erste Byte der Daten ist der Paketzähler 1..20.
Das 2. Byte gibt die Länge des Datenmusters in Byte an.
***************************************************************************/
echoserv echoclient Diese Programme arbeiten zusammen.Fragen
Fragen zum Programm Zyklische Broadcast
Aufgabe 4Datagram-Socket / Fehlermeldung beim Senden von Datagrammen Bearbeiten Sie das Arbeitsblatt
Stream- Sockets
Aufgabe 5ASenden / Empfangen 1.) Testen Sie Stream_Server und Stream_Client
2.) Erweitern Sie den Server so, dass er gleichzeitig mehrere Clientanfragen bearbeiten kann. Für jeden neuen Client soll ein eigener Prozess zur Verfügung gestellt werden.
VorlagenDer Stream_Server (Empfängt Daten und zeigt sie an)
Der Stream_Client ( Sendet Daten an den Stream_Server) Es muss zunächst der Server gestartet werden. Nach dem Start des Servers gibt dieser die PORT-Nummer aus an der er auf Verbindungen wartet. Diese PORT-Nummer muß dem Client beim Start als zweiter Parameter übergeben werden. Als erster Parameter wird dem Client die IP-Adresse des Servers übergeben, an den die Daten des Client gesendet werden sollen.
Beispiel:
1.) Der Server wird auf der ti-voyager (IP-Adresse 141.69.201.205) gestartet. Er liefert als Ausgabe: Socket Port #62995
2.) Der Client wird gestartet : a.out 141.69.201.205 62995
Fragen Angenommen man verwendet den folgenden Aufruf beim Client : a.out 141.69.203.205 62995. Empfängt dann der Server auf der ti-voyager die von diesem Client gesendeten Daten? Begründen Sie dies anhand des Serverprogramms.
Hinweis: Die ti-voyager besitzt die IP-Adressen 141.69.201.205 und 141.69.203.205
Die Behandlung von mehreren Clients durch einen Server mit Hilfe von fork()
Aufgabe 6 |
a.) Testen Sie das Programm "tcp_server2003" ! Als Clients können zunächst Telnet- Sessions verwendet werden. Lassen Sie sich auf dem Rechner, auf dem der Server arbeitet die Prozessliste vor und nach dem Beenden eines Client anzeigen.Der Server muss noch arbeiten. Welche ungewöhnlichen Prozesse tauchen auf? b.) Schreiben Sie Client- Software, die zyklisch (alle 3 Sekunden ) ein Datenpaket an den tcp_server2003 sendet. Das Datenpaket soll einen Integer- Sequenzzähler enthalten. Der Sequenzzähler soll mit jeder Datensendung um den Wert 1 erhöht werden. Ferner soll der Client seine IP-Adresse ermitteln und in der Form wie in sin_addr mitsenden. Paketaufbau: |
|
| Vorlage | tcp_server2003 | |
|
c.) Modifizieren Sie tcp_server2003 so, dass keine Zombies entstehen. Untersuchen Sie dazu das folgende Programm! |
||
Signals |
|
|
| Fragen |
Wozu dient bei Dämonenprozessen
häufig das SIGHUP -Signal? Was läßt sich über die Portierbarkeit der signal()- Funktion sagen? (man signal) |
|
| Vorlage |
/*************************************************************************** * Teste signal-handler * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <signal.h> static void sig_usr(int); int main(void)
{
printf("Hello, world!\n");
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
printf(" Fehler beim Installieren vom SIGUSR1-Signalhandlern");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
printf(" Fehler beim Installieren vom SIGUSR2-Signalhandlern");
printf("Hello-----------, world!\n");
for(;;)
pause();
return EXIT_SUCCESS;
}
static void sig_usr(int signo)
{
if (signo == SIGUSR1)
printf("Signal SIGUSR1 empfangen\n");
else if (signo == SIGUSR2)
printf("Signal SIGUSR2 empfangen\n");
else
printf( "Signal %d empfangen\n", signo);
return;
}
|
Aufgabe H 1
|
struct hostent Ergänzen Sie das vorgegebene Programm so, dass es den DNS-Namen, die IP-Adressen sowie dieAlias- Namen eines Rechners, dessen DNS- Name als Argument übergeben wird, ausgibt
|
|
| Vorlagen |
/***************************************************************************
begin : Son Apr 8 16:52:41 CEST 2001
Ausgabe des Inhaltes der hostent - Information
struct hostent{
char *h_name; Official name of host.
char **h_aliases; Alias list.
int h_addrtype; Host address type.
socklen_t h_length; Length of address.
char **h_addr_list; List of addresses from name server.
}
#define h_addr h_addr_list[0] Address, for backward compatibility.
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netdb.h> // struct hostent
#include <sys/socket.h> // AF_INET
#include <netinet/in.h> // struct in_addr
#include <arpa/inet.h> // inet_ntoa
int main(int argc, char *argv[])
{
char *ptr;
struct hostent *hostptr;
while (--argc > 0){
ptr = *++argv;
if ( (hostptr = gethostbyname(______) ) == NULL){
perror("error gethostbyname \n");
continue;
}//if
printf (" Name des Host: %s\n", hostptr->h__________);
/* Aliasliste ausgeben */
while ( ( ptr = *(hostptr->h_________) ) != NULL){
printf(" alias: %s\n",ptr);
hostptr->h_aliases_______;
}// while h_aliases
/* Adresstyp und Adresslänge ausgeben */
printf(" addr type = %d, addr length = %d\n",
hostptr->h_addrtype, hostptr->h_length);
/* Liste der Internetadressen in dotted notation ausgeben */
switch (hostptr->h_addrtype){
case AF_INET:
pr_inet(hostptr->h_addr_list, hostptr->h_length);
break;
default:
printf("unknown address type\n");
break;
} //switch
}//while argc
return EXIT_SUCCESS;
}
/**************************************************************
Liste der Internetadressen in dotted notation ausgeben
***************************************************************/
void pr_inet (char **listptr, int length){
struct in_addr *ptr;
while ( (ptr =(struct in_addr *) ____listptr_____) != NULL)
printf(" Internet address : %s\n", _________(*ptr));
}
|
|
Stream - Server / Stream - Client II Entwickeln Sie einen Server zum TCP-Sende_Muster_Client!
|
|
| Vorlagen |
Sende_Muster_Client:
|
Sockets: Mit Hilfe von select lesen (non blocking)
Aufgabe nB6 |
Erweitern Sie das Programm "select_read.c" so, daß es sowohl an einem Stream- Socket als auch an einem UDP- Socket Daten ohne zu blockieren entgegennimmt. Verwenden Sie zu diesem Zweck den Select- Systemaufruf. Testen können Sie den Aufbau einer TCP- Verbindung mit Hilfe von Telnet: Telnet Zielrechner Zielport |
|
| Vorlagen | select_read.c | |
Hilfsmittel
Aufgabe H 1 |
struct hostent Ergänzen Sie das vorgegebene Programm so, dass es den DNS-Namen, die IP-Adressen sowie dieAlias- Namen eines Rechners, dessen DNS- Name als Argument übergeben wird, ausgibt
|
|
| Vorlagen |
/***************************************************************************
begin : Son Apr 8 16:52:41 CEST 2001
Ausgabe des Inhaltes der hostent - Information
struct hostent{
char *h_name; Official name of host.
char **h_aliases; Alias list.
int h_addrtype; Host address type.
socklen_t h_length; Length of address.
char **h_addr_list; List of addresses from name server.
}
#define h_addr h_addr_list[0] Address, for backward compatibility.
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netdb.h> // struct hostent
#include <sys/socket.h> // AF_INET
#include <netinet/in.h> // struct in_addr
#include <arpa/inet.h> // inet_ntoa
int main(int argc, char *argv[])
{
char *ptr;
struct hostent *hostptr;
while (--argc > 0){
ptr = *++argv;
if ( (hostptr = gethostbyname(______) ) == NULL){
perror("error gethostbyname \n");
continue;
}//if
printf (" Name des Host: %s\n", hostptr->h__________);
/* Aliasliste ausgeben */
while ( ( ptr = *(hostptr->h_________) ) != NULL){
printf(" alias: %s\n",ptr);
hostptr->h_aliases_______;
}// while h_aliases
/* Adresstyp und Adresslänge ausgeben */
printf(" addr type = %d, addr length = %d\n",
hostptr->h_addrtype, hostptr->h_length);
/* Liste der Internetadressen in dotted notation ausgeben */
switch (hostptr->h_addrtype){
case AF_INET:
pr_inet(hostptr->h_addr_list, hostptr->h_length);
break;
default:
printf("unknown address type\n");
break;
} //switch
}//while argc
return EXIT_SUCCESS;
}
/**************************************************************
Liste der Internetadressen in dotted notation ausgeben
***************************************************************/
void pr_inet (char **listptr, int length){
struct in_addr *ptr;
while ( (ptr =(struct in_addr *) ____listptr_____) != NULL)
printf(" Internet address : %s\n", _________(*ptr));
}
|
|
| Fragen | Interessante Kandidaten für einen
"Hostname", der dem Programm als Argument übergeben
werden kann, sind: www.fh-weingarten.de
oder cb3500.fh-weingarten.de.
Ist als Argument auch eine IP- Adresse erlaubt? Was ist der CNAME Resource Record von www.fh-weingarten.de? Was bedeutet : ptr = *++argv; Ist das so o.k.? Wird nicht das erste Argument überlesen? |
Sockets: Raw Sockets
Aufgabe raw1 |
Raw Socket
Sie haben die Aufgabe zu ermitteln, ob ein Router auf eine ICMP Router Solicitation Message richtig antwortet. Unter www.usadel.de--> Internet1 --> RFCs ist die betreffende RFC abgelegt. Eine Kurzfassung befindet sich im Protokollatlas. |
|
| Vorlagen |
ICMP Router Solicitation Message
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
IP Fields:
Source Address An IP address belonging to the interface
from which this message is sent, or 0.
Destination Address The configured SolicitationAddress.
Time-to-Live 1 if the Destination Address is an IP
multicast address; at least 1 otherwise.
ICMP Fields:
Type 10
Code 0
Ergänzen Sie das folgende Programmfragment so, daß es eine geeignete
ICMP Router Solicitation Message aussendet.
Hinweis: Für das Senden über raw sockets benötigt man root- Rechte.
ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> //memcpy
#define MAXPACKET 20
/*
Structure of ICMP Router Solicitation Message
*/
struct icmp_router_soli{
u_char icmp_type;
u_char icmp_code;
u_short icmp_chksum;
u_long icmp_reserved;
};
int in_chksum(u_short *, int );
int main(void)
{
struct protoent *proto;
struct sockaddr_in name;
struct hostent *hp;
u_char sendpack[MAXPACKET];
struct icmp_router_soli *icp;
int sock;
int packsize;
if ( ( proto = getprotobyname("icmp") ) == NULL) {
perror(" unknown protocol");
exit(1);
}
/* Sende-Socket anlegen */
if ( (sock= socket (AF_INET, SOCK_RAW, proto->p_proto)) <0){
perror("error open socket");
exit(1);
}
hp = gethostbyname(" Ein Router im Segment oder All Routers Multicast " );
if( hp ==(struct hostent *) 0){
printf("error %s: unknown host\n");
exit(2);
}
memcpy((char *) &name.sin_addr, (char *) hp->h_addr, hp->h_length);
name.sin_family=AF_INET;
/*
ICMP Router Discovery zusammenbauen
*/
/* ICMP Pruefsumme berechnen */
/* Datagramm senden */
return EXIT_SUCCESS;
}
/*----------------------------------------------------*/
/* Pruefsumme berechnen */
int in_chksum(u_short *ptr, int nbytes){
long sum;
u_short oddbyte;
u_short answer;
sum = 0;
while (nbytes > 1){
sum += *ptr++;
nbytes -= 2;
}
if (nbytes == 1){
oddbyte = 0;
*((u_char *) &oddbyte) = *(u_char *)ptr;
sum +=oddbyte;
}
/*
Add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >>16) + (sum & 0xffff); //add high-16 to low-16
sum += (sum >>16); // add carry
answer = ~sum ;// ones-complement
return(answer);
}
|
|