Kapitel 16. Netværkskommunikation

Indhold:

Kapitlet forudsættes ikke i resten af bogen.

Forudsætter Kapitel 15, Datastrømme og filhåndtering.

Alle maskiner på et TCP-IP-netværk, f.eks. internettet, har et IP-nummer. Det er en talrække på fire byte, der unikt identificerer en maskine på nettet, f.eks. 195.215.15.20.

Normalt bruger man en navnetjeneste (eng.: Domain Name Service - DNS), der sammenholder alle numre med navne, der er nemmere at huske, f.eks. www.cv.ihk.dk eller www.esperanto.dk. Adressen localhost (IP-nummer 127.0.0.1) er speciel ved altid at pege på den maskine, man selv sidder ved.

Kommunikation mellem to maskiner sker ved, at værtsmaskinen (eng.: host) gør en tjeneste (eng.: service) tilgængelig på en bestemt port, hvorefter klienter kan åbne en forbindelse til tjenesten.

Figur 16-1. Java

Hjemmesider (HTTP-tjenesten) er tilgængelige på port 80. Filoverførsel (FTP-tjenesten) er på port 21, og hvis man vil logge ind på maskinen (telnet-tjenesten), er det port 23.

I det følgende vil vi vise, hvordan man bruger og udbyder HTTP-tjenesten til hjemmesider, men andre former for netværkskommunikation foregår på lignende måder.

16.1. At forbinde sig til en port

Man opretter en forbindelse ved at oprette et Socket-objekt og angive værtsmaskinen og porten i konstruktøren. Vil man f.eks. kontakte webserveren på www.esperanto.dk, skriver man:


  Socket forbindelse = new Socket("www.esperanto.dk",80);

Hvis alt gik godt, har Socket-objektet (forbindelsen eller "soklen") nu kontakt med værtsmaskinen (ellers har den kastet en undtagelse).

Nu skal vi have fat i datastrømmene fra os til værten og fra værten til os:


  OutputStream fraOs = forbindelse.getOutputStream();
  InputStream tilOs = forbindelse.getInputStream();

Hvis vi vil sende/modtage binære data, kan vi nu bare gå i gang: fraOs.write() sender en byte eller en række af byte til værten, og med tilOs.read() læser vi en eller flere byte.

Hvis det er tekstkommunikation, er PrintWriter og BufferedReader (der arbejder med tegn og strenge som beskrevet tidligere) dog nemmere at bruge :


  PrintWriter ud = new PrintWriter(fraOs);
  BufferedReader ind = new BufferedReader(new InputStreamReader(tilOs));

Nu kan vi f.eks. bede værten om at give os startsiden (svarende til adressen http://www.esperanto.dk/). Det gøres ved at sende linjen "GET / HTTP/0.9", derefter "Host: www.esperanto.dk" og til sidst en blank linje:


  ud.println("GET / HTTP/0.9");
  ud.println("Host: www.esperanto.dk");
  ud.println();
  ud.flush();

Kaldet til flush() sikrer, at alle data er sendt til værten, ved at tømme eventuelle buffere.

Nu sender værten svaret, der kan læses fra inddatastrømmen:


  String s = ind.readLine();
  while (s != null) {
    System.out.println("svar: "+s);
    s = ind.readLine();
  }

While-løkken bliver ved med at læse linjer. Når der ikke er flere data (værten har sendt alle data og lukket forbindelsen), returnerer ind.readLine() null, og løkken afbrydes.

Her er hele programmet:


import java.io.*;
import java.net.*;
public class HentHjemmeside
{
  public static void main(String arg[])
  {
    try {
      Socket forbindelse = new Socket("www.esperanto.dk",80);
      OutputStream fraOs = forbindelse.getOutputStream();
      InputStream  tilOs = forbindelse.getInputStream();
      PrintWriter    ud  = new PrintWriter(fraOs);
      BufferedReader ind = new BufferedReader(new InputStreamReader(tilOs));
      ud.println("GET / HTTP/0.9");
      ud.println("Host: www.esperanto.dk");
      ud.println();
      ud.flush();              // send anmodning afsted til værten
      String s = ind.readLine();
      while (s != null)        // readLine() giver null når datastrømmen lukkes
      {
        System.out.println("svar: "+s);
        s = ind.readLine();
      }
      forbindelse.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Resultatet bliver:


svar: HTTP/1.1 200 OK
svar: Date: Tue, 17 Apr 2001 13:06:06 GMT
svar: Server: Apache/1.3.12 (Unix)  (Red Hat/Linux) PHP/4.0.2 mod_perl/1.24
svar: Last-Modified: Thu, 05 Mar 1998 17:28:16 GMT
svar: Accept-Ranges: bytes
svar: Content-Length: 896
svar: Content-Type: text/html
svar:
svar: <HTML><HEAD><TITLE>Esperanto.dk</TITLE>
svar: <META name="description" content="Den officielle danske hjemmeside om plansproget esperanto. Oficiala dana hejmpagxo pri la planlingvo Esperanto.">
svar: <META name="keywords" content="Esperanto, Danmark, DEA, UFFE, Esperanto-nyt, bogsalg, plansprog, kunstsprog, lingvistik, videnskab, debat, Zamenhof, Danio, libroservo, planlingvo, teknika lingvo, lingvistiko, debato">
svar: </HEAD>
svar:
svar: <FRAMESET cols="22%,*"                  >
svar: <FRAME name="menu"    src="da/menu.htm"     marginwidth=0>
svar: <FRAME name="indhold" src="da/velkomst.htm">
svar: <NOFRAMES>
svar: Velkommen til Esperanto.dk!
svar: <p>
svar: Gå til <a href="da/velkomst.htm">velkomst-siden</a> eller til
svar: <a href="da/menu.htm">indholdsfortegnelsen</a>,
svar:
svar: </NOFRAMES>
svar: </FRAMESET>
svar:
svar: </html>

Det ses, at svaret starter med et hoved med metadata, der beskriver indholdet (dato, værtens styresystem, hvornår dokumentet sidst blev ændret, længde, type).

Derefter kommer en blank linje og så selve indholdet (HTML-kode).

Dette er i overensstemmelse med måden, som data skal sendes på ifølge HTTP-protokollen. Protokollen er løbende blevet udbygget. En af de tidligste (og dermed simpleste) var HTTP/0.9, mens de fleste moderne programmer bruger HTTP/1.1.