kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Internetprogrammierung mit Java

(EN google-translate)

(PL google-translate)

Das Schichtenmodell von TCP (Transmission Control Protocol)

  1. Verbindungsschicht
  2. Vermittlungsschicht
  3. Transportschicht
  4. Anwendungsschicht

In jeder Schicht werden Protokolle definiert, wie Daten zu übertragen sind. Protokolle der Schicht 4, der Anwendungsschicht sind beispielsweise HTTP (Hypertext Transfer Protocol), FTP (File Transfer Protocol) oder SMTP (Simple Mail Transfer Protocol).

Das Versenden der Daten über das Internet erfolgt mittels aufeinander aufbauender Protokolle über die Schichten hinweg. Zu sendende Daten werden von der Anwendungsschicht an die Transportschicht übergeben. Gemäß dem TCP (Transmission Control Protocol) werden hier die zu sendenden Daten in Pakete aufgeteilt, mit einem Datenkopf versehen und an Schicht 2, der Vermittlungsschicht übergeben.

In der Schicht 2, der Vermittlungsschicht, ist das Protokoll IP (Internet Protocol) enthalten. In dieser Schicht wird den Datenpaketen ein IP-Header hinzugefügt, über den dann der Rechner identifiziert werden kann, an den die Daten geschickt werden sollen. Dann werden die Pakete weiter an die Schicht 1, der Verbindungsschicht übergeben.

Auf Schicht 1, der Verbindungsschicht, sitzt die Netzwerkkarte. Sie packt einen Daten-Rahmen um die Pakete.

Auf der Empfängerseite findet dieser Vorgang in umgekehrter Reihenfolge satt. D.h. die Daten kommen auf Schicht 1 an und wandern nach entsprechendem Entpacken immer eine Schicht höher.

UDP

Auf der Transportschicht Ebene (Schicht 3) kann alternativ das TCP (Transmission Control Protocol) oder das UDP (User Datagram Protocol) verwendet werden.

Der Vorteil von TCP ist, dass über Fehlersummen fehlerhafte Übertragungen von Paketen erkannt und diese erneut angfragt werden können. Außerdem ist gewährleistet, dass die Pakete in der richtigen Reihenfolge empfangen werden, in der sie gesendet wurden. TCP ist ein Verbindungsorientiertes Protokoll.

UDP besitzt keine Kontrolle über auftretende Fehler und die Paketreihenfolge. Das Protokoll ist entsprechend einfacher und damit auch schneller. UDP ist ein verbindungsloses Protokoll.

Deshalb wird TCP auch hauptsächlich zur Übermittlung von Internetseiten benutzt: Die Vorgänge hier stellen keine höheren Anforderungen an die Übertragungsgeschwindigkeit, müssen aber in der Regel vollkommen korrekt übertragen werden (Beispiel: Daten für eine Bestellung oder Flugbuchung über das Internet.)

Werden aber beispielsweise Filme oder Audiodaten direkt über das Internet geschickt (Streaming), so macht es nichts, wenn in den übertragenen Daten kleinere Fehler auftauchen. Jedoch sollte gewährleistet sein, dass die Übertragungsgeschwindigkeit den Anforderungen des Mediums entspricht. Hier bietet es sich eher an UDP zu verwenden.

IP, DNS und Portnummer

Zur Identifikation eines Netz-Rechners benötigt dieser eine IP-Adresse. Dies ist eine aus vier 8-Bit-Zahlen zusammengesetzte Kennung. Es gibt IP-Adressen der Klassen A, B und C.

  • Klasse A nutzt die oberen 8 Bit zur Netzwerkkennung und den Rest als Rechneradresse, 0.0.0.0 - 127.255.255.255.
  • Klasse B nutzt die oberen 16 Bit zur Netzwerkkennung und den Rest als Rechneradresse, 128.0.0.0 - 191.255.255.255.
  • Klasse C nutzt die oberen 24 Bit zur Netzwerkkennung und den Rest als Rechneradresse, 192.0.0.0 - 223.255.255.255.

Der Netzwerkadressbereich wird in einer Netzmaske mit Einsen maskiert. Klasse C-Beispiel: 170.19.0.33, Netzwerkmaske: 255.255.0.0

Ein DNS-Server (Domain Name Server) setzt die IP-Adressen in lesbare Namen und umgekehrt. Jeder Rechner kann sich selber als "localhost" oder als IP-Adresse 127.0.0.1 "sehen".

Unter der selben IP-Adresse können mehrere Server ihren Dienst versehen. Sie können aber auf unterschiedlichen Datenkanälen, den so genannten Ports arbeiten. Portnummern können die ganzen Zahlen zwischen 0 und 65535 annehmen. Die Portnummern 0 bis 1023 sind weltweit eindeutig definiert. Beispiele:

Port Service Beschreibung
7 echo Wiederholt eine Eingabe als Antwort
13 daytime liefert die Systemzeit eines Servers
21 FTP Übertragung von Dateien
80 HTTP Auslieferung von Internetseiten

Tabelle 0-1: Feste Portzuordnungen verschiedener Web-Services

Formulare

Die wohl bekannteste Möglichkeiten, Daten mit einem Server auszutauschen, besteht in der Verwendung von Formularen. Diese werden in einer Webseite eingebettet und erlauben es die eingetragenen Formulardaten an einen Server zu schicken. Dieser liefert daraufhin eine neue Version der ursprünglichen Webseite aus, z.B. ergänzt mit Daten aus einer Datenbank oder nach einem Login mit nun freigeschalteten Daten. Formulardaten werden über das HTTP-Protokoll geschickt. Beispiel: Login-Formular auf dieser Webseite.

Java

Die Java-API bietet Internetverbindungen auf verschiedenen Abstraktionsebenen. D.h. es gibt in den einzelnen Library-Klassen Methoden, die elementare Dinge umsetzen, wie eine Netzwerkverbindung aufbauen, aber auch solche, die auf einem sehr hohen Abstraktionslevel stehen und die darunter liegenden Vorgänge verbergen, wie z.B. eine Methode eines auf einem anderen Rechner liegenden Objektes zu benutzen (RMI - Remote Method Invocation). Beispiele:

  • Herunterladen einer Internetseite als String-Objekt.
  • Datenaustausch über UDP.
  • Simulation des Versendens von HTML-Formulardaten.
  • Einbinden entfernter Objekte und Benutzung derer Methoden (RMI).

Im folgenden sollen die diversen Techniken anhand kleiner Experimente erlernt werden.

Experiment Nr.1 - Formulardaten verarbeiten

Ein einfacher Weg, an einen Server zu kommen, ist die Möglichkeit einen XAMPP-Server zu installieren. Dies stellt eine funktionierende out-of-the-box-Lösung dar in der bereits ein Apache-Server, eine MySQL-Datenbank, sowie die Webprogrammiersprachen PHP und Perl funktionierend miteinander interagierend vorhanden sind.

Zu Experimentierzwecken kann man sich XAMPP aus dem Internet herunterladen und installieren und anschließend eine php-Internetseite in das Verzeichnis htdocs legen. Alle Seiten, die dort liegen, können nach Start des Servers übe Angabe der IP-Adresse und nachfolgend des Pfades ab htdocs von einem Client-seitigen Web-Browser abgerufen werden, sofern dies von dem Server erlaubt wird. Beispiel:

Wir legen in htdocs ein Dokument test.html mit folgendem Inhalt:

<html>
    <head>
    </head>
    <body>
        <h1>Dies ist die Internetseite test.html</h1>
        <br/> 
        <p>Senden Sie einen kurzen Text an test2.php:</p>
        <br/>
        <form action="http://localhost/test2.php" method="POST">
            Text senden: <input type="text" name="meintext" value=""/>
            Text abschicken: <input type="submit" value="go"/>
        </form>
    </body>
</html>

Code 0-1: Datei test.html in htdocs des XAMPP-Servers.

Wie am Code zu interpretieren ist, werden die gesendeten Daten Server seitig von einer PHP-Datei verarbeitet, die den Namen test2.php trägt (weitere Erläuterungen s. Vorlesung). Diese könnte so aussehen:

Datei test2.php in htdocs des XAMPP-Servers.

Bild 0-1: Datei test2.php in htdocs des XAMPP-Servers.

Experiment Nr.2 - Inhalt einer Internetseite mit Java abrufen

Applets sind prädestiniert dazu Client-Aufgaben zu übernehmen, da sie selbst wiederum in Internetseiten eingebunden werden können. Ihre Verwendung unterliegt aber einigen Beschränkungen:

  • Applets können nicht direkt auf Dateien auf dem Server oder Client zugreifen.
  • Applets können nur mit dem Server kommunizieren, von dem aus sie ausgeliefert wurden.

Das folgende Applet liest den Quelltext der Seite http://www.kramann.info/test.html als String aus und stellt den Inhalt in einem Textfenster (TextArea) und als HTML-Seite (JTextPane) dar. Nach Aufbau der Verbindung wird ein Datenstrom geöffnet und der Inhalt der Seite heruntergeladen.

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.TextArea;
import java.awt.ScrollPane;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.html.HTMLEditorKit;

import java.io.*;
import java.net.*;

public class Htmlseite2 extends Applet
{
    public String uebergabe = "";

    public void init()
    {
    }

    public void start()
    {
        try
        {
            URL url = new URL("http://www.kramann.info/test.html");
            URLConnection verbindung = url.openConnection();
            verbindung.setUseCaches(false);
            DataInputStream datenstrom = new DataInputStream(verbindung.getInputStream());
            String zeile;
            while( (zeile=datenstrom.readLine()) != null )
                uebergabe+=zeile+"\n";
        }
        catch(Exception e)
        {
            uebergabe = e.toString();
        }
        setLayout(null);


        ScrollPane scrollpane = new ScrollPane();
        scrollpane.setBounds(0,0,600,200);
        TextArea textarea = new TextArea();
        textarea.setText(uebergabe); 
        scrollpane.add(textarea);
        add(scrollpane);

        ScrollPane scrollpane2 = new ScrollPane();
        scrollpane2.setBounds(0,220,600,200);
        JTextPane textarea2 = new JTextPane();
        textarea2.setEditorKit(new HTMLEditorKit());
        textarea2.setText(uebergabe); 
        textarea2.setContentType("text/html");
        scrollpane2.add(textarea2);
        setLayout(null);
        add(scrollpane2);
       
    }


    public static void main(String[] args)
    {
        Htmlseite2 hb = new Htmlseite2();
        hb.init();
        hb.start();
        hb.repaint();
        JFrame mF = new JFrame("Website laden");
        mF.getContentPane().add(hb);
        mF.pack();
        mF.setSize(630,430);
        mF.setLocation(10,10);
        mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mF.setVisible(true);
    }
    
}

Code 0-2: Applet Htmlseite2.java

Damit das Applet in die vorliegende HTML-Seite eingebettet werden kann, muß in diese ein Applet-Tag in folgender Weise eingetragen werden:

<applet code="Htmlseite2.class" width="700" height="450">
</applet>

Code 0-3: Applet-Tag für Htmlseite2.

Der Start dieses Applets mit dem appletviewer führt jedoch zu einem Fehler:

  • java.security.AccessControlException: access denied ("java.net.SocketPermission" "www.kramann.info:80" "connect,resolve")

Mit anderen Worten: Einem Applet ist es nicht erlaubt eine fremde HTML-Seite zu laden (Sandboxprinzip).

Startet man das gleiche Programm aber als Applikation, so funktioniert es:

Htmlseite2 als Applikation gestartet.

Bild 0-2: Htmlseite2 als Applikation gestartet.

Experiment Nr.3 - Laden von Bildern

Beispielsweise Bilder einer USB-Kamera könnten zyklisch aufgefrischt werden und könnten über ein Thread von einem Client-seitigen Java-Programm geholt werden. Die Art der versendeten Daten kann über den so genannten MIME-Typ (Multipurpose Internet Mail Extension) bestimmt werden. Allerdings bietet die Klasse unmittelbar eine Methode an, die ein Bild über eine URL lädt:

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.TextArea;
import java.awt.ScrollPane;
import java.awt.Image;
import java.net.URL;
import java.net.URI;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import java.awt.Toolkit;

public class Bildladen extends Applet
{
    ImageIcon img = null;
    Image bild = null;
    public String uebergabe = "";
    public byte[] bildbytes = null;
    public void start()
    {
        try
        {
            try
            {
                URL url = new URL("http://www.kramann.info/ch.png");
                Toolkit tk = Toolkit.getDefaultToolkit();             
                bild = tk.createImage(url);
                img = new ImageIcon(tk.createImage(bild.getSource()));
                repaint();
             }
            catch(Exception e)
            {
                System.out.println(e);
            }
        }
        catch(Exception e)
        {
        }
    }

    public void paint(Graphics g)
    {
        if(bild!=null)
            g.drawImage(bild, 0, 0, this); 
    }

    public static void main(String[] args)
    {
        Bildladen hb = new Bildladen();
        hb.init();
        hb.start();
        hb.repaint();
        JFrame mF = new JFrame("Website laden");
        mF.getContentPane().add(hb);
        mF.pack();
        mF.setSize(630,430);
        mF.setLocation(10,10);
        mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mF.setVisible(true);
    }
}

Code 0-4: Applet Bildladen.java

Auch hier wird nicht erlaubt das Bild zu laden, wenn die Anwendung als Applet gestartet wird. Als Applikation funktioniert es:

Fenster anch Start von Bildladen als Java-Applikation.

Bild 0-3: Fenster anch Start von Bildladen als Java-Applikation.

Simulation eines POST-Formulars mit Java

package info.kramann.crossplattform.divers;

import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
*  <h4>Serverkommunikation.java</h4>
*
*  Copyright (C) 2015 Guido Kramann<br/>
*  kramann@fh-brandenburg.de<br/>
*  http://www.kramann.info<br/>
*  <br/>
*/
public class Serverkommunikation
{
    public   String post(String[] name, String[] value, String in_url)
    {
System.out.println("***** Serverkommunikation.class: String post(String[] name, String[] value, String in_url) *****");

                if(name==null || value==null || name.length==0 || value.length==0 
                || name.length!=value.length || in_url==null || in_url.length()==0)
                {
                    System.out.println("Ungültige Übergabeparameter in class Internet, Methode String post(String[] name, String[] value, String url)");
                    return null;
                }

                for(int i=0;i<name.length;i++)
                {
                    if(name[i]==null || name[i].length()==0 || value[i]==null)
                    {
                       System.out.println("Unvollständige Übergabeparameter in class Internet, Methode String post(String[] name, String[] value, String url)");
                       return null;
                    }
                }

                try 
                {
                    String data = "";

                    for(int i=0;i<name.length;i++)
                    {
                        if(i>0)
                            data += "&";
                        data += URLEncoder.encode(name[i], "UTF-8") + "=" + URLEncoder.encode(value[i], "UTF-8");
                    }
                    URL url = new URL(in_url);
                    URLConnection conn = url.openConnection();
                    conn.setDoOutput(true);
                    OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
                    wr.write(data);
                    wr.flush();

                    //Antwort laden:
                    BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                    StringBuffer gelesen = new StringBuffer();
                    String zeile="";
                    int anz=0;
                    boolean ok_sichern = true;
                    while ((zeile = rd.readLine()) != null) 
                    {
                        zeile = zeile.trim();
                        if(zeile!=null)
                        {
//System.out.println("Empfanene Zeile: "+zeile);
                            gelesen.append(zeile);    
                            gelesen.append("
");
                        }
                    }

                    wr.close();
                    rd.close();                    
System.out.println("Daten zur Auswertung empfangen:
"+gelesen.toString());
                   
                    String ausgabe = gelesen.toString();

                    if(  ausgabe!=null && ausgabe.length()>0 && !(ausgabe.length()>=5 && ( ausgabe.substring(0,5)).equals("ERROR") )  )
                    {
//Weiterverarbeitung (Darstellung der Punkte in Bildansicht)
System.out.println("Weiterverarbeitung der empfangenen Daten.");
                        return ausgabe;
                    }
                    else
                    {
                        System.out.println("Es wurde keine lesbare Daten empfangen.");
                        return null;
                    }
                }
                catch(Exception e)
                {
                    System.out.println(e);
                    return null;
                }
    }
    
    public static void main(String[] args)
    {
        Serverkommunikation server = new Serverkommunikation();

        String ping=server.post(new String[] {"test"},new String[] {"test"}, "http://localhost/kurzschrift/ping.php");
        System.out.println("http://localhost/kurzschrift/ping.php liefert:\""+ping+"\"");
    
    }
}

Code 0-5: Simulation eines POST-Formulars mit Java.