Socketprogrammierung

Linux


Datagram- Sockets


Aufgabe 1
 Datagram-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 2
 Datagram-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

Vorlage
 Siehe Aufgabenblatt

 timeprotocol  muss mit einem Argument ( = Zielrechner ) gestartet werden!

 



Aufgabe 3
Datagram-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 4
Datagram-Socket / Fehlermeldung beim Senden von Datagrammen

Bearbeiten Sie das Arbeitsblatt

   

Stream- Sockets

 

Aufgabe 5A
 Senden / 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.

 

 
Vorlagen
Der 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:
Bytes   1 -   4  : Sequenzzähler in Network-Byte-Order.
Bytes   5 -   8  : Die IPAdresse des Client in Network-Byte-Order
Bytes   9 - 29 : Eine Zeichenkette, die kein \0 und kein $ enthalten darf
Byte           30: \n

Vorlage  tcp_server2003
   
c.) Modifizieren Sie tcp_server2003 so, dass keine Zombies entstehen. Untersuchen Sie dazu das folgende Programm!
 
 

Signals
  1. Senden Sie an das folgende Programm die Signale SIGUSR1 bzw. SIGUSR2. Wie verhält sich das Proramm?
  2. Verändern Sie das Programm so, dass es das Signal SIGHUP abfängt und beim Empfang dieses Signal die Meldung "SIGHUP aufgerufen" ausgibt. Installieren Sie ferner für SIGUSR1 und SIGUSR2 getrennte Handler.
  3. Wie verhält sich das Programm, wenn Sie SIGALRM senden? Modifizieren Sie das Programm so, dass es SIGALRM ignoriert. Wie verhält sich das Programm nun?
  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);
}