22. Hálózatkezelés

22.1 Hálózati alapok

Az Internetre kötött számítógépek vagy a TCP (Transmission Controll Protocol) vagy az UDP (User Datagram Protocol) protokollt használják, amint azt az alábbi ábrán is látni lehet:

Protokols

Ha egy Java programot írunk, ami használja a hálózatot, a felhasználói réteget programozzuk. Általában nincs szükség a TCP vagy az UDP protokollok közvetlen használatára, ehelyett használhatjuk az osztályokat a java.net csomagból. Ezek az osztályok rendszerfüggetlen hálózati kommunikációt biztosítanak. Ha szeretnénk tudni, hogy a programunk pontosan melyik osztályokat kell, hogy használja, meg kell érteni az alapvető különbségeket a TCP és az UDP protokollok között.

22.1.1 TCP

Ha két program megbízhatóan akar egymással kommunikálni, létrehoznak egy kapcsolatot, és ezen keresztül küldik az adatokat, hasonlóan a telefon működéséhez. A TCP – akár egy telefontársaság – garantálja, hogy az adat, amit küldünk, helyes sorrendben (!) megérkezik a vevőhöz. Ha ez nem sikerül, hibajelzést küld vissza.

A TCP egy megbízható pont-pont csatornát ad azoknak az alkalmazásoknak, amelyek megbízható kapcsolatot kívánnak meg. Ilyen alkalmazások például: Hyper Text Transfer Protokoll (HTTP), File Transfer Protokoll (FTP) és a Telnet. A hálózaton átküldött és fogadott adatok sorrendje elengedhetetlen az alkalmazások helyes működéséhez. Mikor a HTTP-t egy URL-ből való olvasáshoz használjuk, az adatokat olyan sorrendben kell kiolvasnunk, ahogy azt küldték, különben könnyen lehetne az eredmény egy összekuszált HTML fájl, hibás ZIP fájl, vagy valami más érvénytelen információ.

Definíció: a TCP (Transmission Controll Protocol) egy kapcsolat alapú protokoll, ami az adatok megbízható folyamát adja két számítógép között.

22.1.2 UDP

Az UDP nem ad megbízható kapcsolatot egy hálózaton levő két számítógép között, mivel ez nem kapcsolat alapú, mint a TCP, inkább az adatok független csomagjait küldi az alkalmazások között. Ezeket a csomagokat adatcsomagoknak is hívjuk. A adatcsomagok küldése leginkább a levelek postán át való küldéséhez hasonlít: a szállítás nem garantált, a sorrend nem fontos, és mindegyik üzenet különbözik a másiktól.

Definíció: az UDP (User Datagram Protocol) egy olyan protokoll, ami az adatok olyan független csomagjait továbbítja egyik számítógépről a másikra, amiket adatcsomagoknak hívunk, és nincs garancia a megérkezésükre. Az UDP nem kapcsolat alapú, mit a TCP.

Számos alkalmazásnál a megbízhatóság garantálása kritikus, hogy az információ eljusson a hálózat egyik végéről a másikra. Mindemellett a kommunikáció egyéb formái nem kívánnak meg olyan szigorú normákat.

Nézzünk például egy óraszervert, ami a pontos időt küldi el a klienseknek, ha azok igénylik. Ha a kliens hiányol egy csomagot, nem szükséges újraküldeni azt, mert az idő pontatlan lesz, ha második próbálkozásra kapja meg. Mikor a kliens két kérést irányít a szerver felé, és a csomagokat rossz sorrendben kapja, a kliens észreveszi ezt, és újabb kérést küld. A megbízható TCP protokoll ebben az esetben nem szükséges, mivel az a teljesítmény rovására mehet, és esetleg csak akadályozza a szolgáltatást.

A ping parancs egy másik kitűnő példa olyan szolgáltatásra, ami nem igényel megbízható csatornát. A parancs teszteli egy hálózaton levő két számítógép közötti kapcsolatot. A parancsnak tudnia kell, hogy a csomag megérkezett-e, hogy megállapítsa, működik-e a kapcsolat. Egy megbízható csatornán ez a szolgáltatás se működik megfelelően.

Megjegyzés: Sok tűzfal és router úgy van konfigurálva, hogy ne engedje át az UDP csomagokat. Ha problémánk van egy, a tűzfalon kívül levő szolgáltatáshoz való kapcsolódással, vagy a kliens nem tud hozzád csatlakozni, engedélyezzük az UDP kapcsolatokat.

22.1.3 A portokról általánosságban

Ha nagyvonalakban akarunk beszélni, azt mondjuk, a számítógép egy egyszerű fizikai kapcsolaton keresztül kapcsolódik a hálózatra. Minden adat ezen a kapcsolaton keresztül érkezik, bár az adatok a számítógép különböző programjait használják. Honnan tudja a számítógép, hogy melyik alkalmazásnak melyik adatot kell továbbítani? A portok használata által.

Az adat, amit az interneten keresztül küldenek, el van látva címzési információval, ami azonosítja a célszámítógépet és a portját. A számítógép a 32 bites IP címmel van azonosítva, melyet arra használunk, hogy az adat a megfelelő számítógépre érkezzen meg. A portot egy 16 bites számmal azonosítjuk, amit a TCP vagy UDP arra használ, hogy az adat a megfelelő programhoz jusson.

A kapcsolat alapú kommunikációnál, mint amilyen a TCP, a szerver program leköt egy foglalatot egy jellemző portnak. Ennek eredményeképpen a szerver megkap minden adatot, ami ezen a porton keresztül érkezik. A kliens ezután kommunikálhat a szerverrel a megadott porton keresztül, amit az alábbi ábra illusztrál:

Server-Client TCP

Definíció: a TCP és az UDP protokollok portokat használnak, hogy a bejövő adatokat a számítógép megfelelő programjai felé irányítsák.

Az adatcsomag alapú kommunikációnál, mint amilyen az UDP, az adatcsomag csomagok tartalmazzák a célállomás portszámát, és az UDP irányítja a megfelelő helyre a csomagot.

Csomagok portra irányítása

A portok a 0 - 65535 intervallumba kell, hogy essenek, mivel 16 bites számként vannak ábrázolva. A 0 és 1023 közötti portok fent vannak tartva olyan ismert szolgáltatásoknak, mit például a HTTP vagy az FTP vagy más rendszerszolgáltatás. Ezeket a portokat jól ismert portoknak hívjuk. A saját programjainknak nem szabad lekötni őket.

22.1.4 Hálózati osztályok a JDK-ban

A java programok használhatják a java.net osztályain keresztül a TCP vagy UDP protokollokat, hogy kommunikáljanak az Interneten. Az URL, URLConnection, Socket és ServerSocket osztályok mindegyike a TCP-n keresztül kommunikál, míg a DatagramPacket, DatagramSocket és MulticastSocket osztályok az UDP protokollt használják.

22.2 URL-ek kezelése

Ha már szörfözött a weben, kétségtelenül hallott már az URL-ről, és használta is a HTML oldalakhoz való hozzáférésekhez. A legegyszerűbb arra gondolni, hogy az URL egy fájlra mutat a weben, azonban ez nem teljesen helyes megállapítás. Az URL más erőforrásokra is tud mutatni, például adatbázis lekérdezésekre és parancs kimenetekre.

Definíció: az URL (Uniform Resource Locator) az interneten található erőforrásokra tud hivatkozni.

A következő ábra egy olyan URL-t mutat, ami a Java weboldalára mutat, amit a Sun Microsystems üzemeltet:

URL Összetevői

Ahogy látszik is, az URL két fő komponensből tevődik össze:

  • Protokollazonosító (Protocol identifier)
  • Erőforrás neve (Resource name)

Jegyezzük meg, hogy a protokoll azonosító és az erőforrás neve kettősponttal és két perjellel van elválasztva. A protokoll azonosító azt a protokollt jelzi, ami eléri a kívánt erőforrást. A fenti példa a Hypertext Transfer Protocol-t (HTTP) használja, amit weboldalak eléréséhez használunk. A HTTP csak egy a sok különböző protokoll közül. Használjuk még a File Transfer Protocol-t (FTP), a Gopher, File, News protokollokat.

Az erőforrás neve tartalmazza az erőforrás pontos címét. A formája függ a használt protokolltól, de a legtöbb protokoll esetében az erőforrás nevében benne van az alábbi komponensek közül legalább egy.

Hosztnév A gép neve, amelyen az erőforrás van
Fájlnév Az elérési út neve a hoszton
Portszám Az a portszám, amelyikre csatlakozni akarunk
Hivatkozás (horgony) Ha a fájlon belül akarunk elérni valamit

A legtöbb protokollnál a hosztnév és a fájlnév kötelező, míg a portszám és a hivatkozás csak opcionális. Például az erőforrás név egy HTTP típusú URL-ben megad egy szervert a hálózaton (hosztnév) és a dokumentum elérési útját a gépen (fájlnév), esetleg megad egy portszámot és egy hivatkozást (horgonyt). A Java weboldal URL-ben a java.sun.com a hosztnév.

22.2.1 URL objektum létrehozása

URL objektumot legegyszerűbben egy olyan sztringből tudunk előállítani, ami ember számára olvasható formában tartalmazza az URL címet. Ez általában olyan alak, hogy más is felhasználhatja az URL-t. Például a Gamelan oldal URL-e, ami Java forrásokat használ, a következőképpen néz ki:

http://www.gamelan.com/[/codefilter_code]

A Java programban a következőt kell használni, hogy URL objektumot hozzunk létre:

URL gamelan = new URL("http://www.gamelan.com/");

A fenti URL objektum egy abszolút URL. Az abszolút URL minden információt tartalmaz, ami szükséges lehet, hogy elérjük a forrást. Ezen kívűl létre lehet hozni objektumokat relatív URL címmel is.

Relatív URL létrehozása

A relatív URL-eket gyakran a HTML fájlokon belül használjuk. Például tegyük fel, hogy írtunk egy HTML fájlt, aminek a neve JoesHomePage.html. Az oldalon belül vannak linkek más oldalakra, pl. PicturesOfme.html és MyKids.html, amik ugyanazon a gépen és ugyanabban a könyvtárban vannak, mint a JoesHomePage.html fájl. A linkek meghatározhatóak fájlnévként, amit a következő programrészlet mutat be:

<a href="PicturesOfMe.html">Pictures of Me</a>
<a href="MyKids.html">Pictures of My Kids</a>

Ezek relatív URL címek, ahol az URL arra a szerverre hivatkozik, ahol a JoesHomePage oldal is található.

A Java programokban létrehozhatunk URL objektumokat relatív URL-ből is. Például tegyük fel, hogy ismerünk két URL-t a Gamelan oldalról.

http://www.gamelan.com/pages/Gamelan.game.html
http://www.gamelan.com/pages/Gamelan.net.html

Hozzunk létre URL objektumot ezekből az oldalakból, hivatkozva a közös könyvtárukra (http://www.gamelan.com/pages/), mit itt:

URL gamelan = new URL("http://www.gamelan.com/pages/");
URL gamelanGames = new URL(gamelan, "Gamelan.game.html");
URL gamelanNetwork = new URL(gamelan, "Gamelan.net.html");

Ez a kódrészlet az URL azon konstruktorát használja, amivel létrehozhatunk egy URL objektumot egy másik alapján. A konstruktor általános alakja a következő:

URL(URL baseURL, String relativeURL)

Az első paraméter egy URL objektum, ami az új URL bázisát jelzi. A második paraméter egy sztring, ami specifikálja a bázisra hivatkozó forrás nevét. Ha a baseURL nincs megadva, a konstruktor abszolút URL-ként kezeli a relativeURL sztringet. Viszont, ha a relativeURL sztring egy abszolút URL, a konstruktor figyelmen kívül hagyja a baseURL-t.

Ez a konstruktor akkor is hasznos lehet, ha olyan URL objektumot akarunk létrehozni, amiben van horgony (anchor). Tegyük fel, hogy a Gamelan.network.html fájl tartalmaz egy horgonyt, amit BOTTOM-nak hívnak, és a fájl aljára mutat. A következő kód a relatív URL konstruktort használja az objektum létrehozására:

URL gamelanNetworkBottom = new URL(gamelanNetwork, "#BOTTOM");

Más URL konstruktorok

Az URL osztály tartalmaz két másik konstruktort is az URL objektumok létrehozásához. Ezek a konstruktorok akkor hasznosak, ha olyan URL-ekkel dolgozunk, mit például a HTTP, ami tartalmaz hosztnevet, fájlnevet, portszámot és hivatkozást (horgonyt) is. Ez a két konstruktor akkor is hasznos lehet, ha nincs egy olyan sztringünk, ami tartalmazza a komplett URL-t, de ismerjük néhány összetevőjét.

Például feltételezzük, hogy egy hálózat-tallózó panelt fejlesztünk éppen, ami hasonlóan működik, mint egy fájltallózó, vagyis a felhasználó választhat protokollt, hosztnevet, portot és fájlnevet. Létrehozhatunk URL-t a panel komponenseiből. Az első konstruktor az URL-t a protokollból, a hosztnévből, és a fájlnévből állítja elő. Az alábbi példa a Gamelan.net.html fájlból (ami a gamelan oldalon található meg) csinál URL-t.

new URL("http", "www.gamelan.com", "/pages/Gamelan.net.html");

Ez ekvivalens a következővel:

new URL("http://www.gamelan.com/pages/Gamelan.net.html");

Az első paraméter a protokoll, a második a hosztnév és az utolsó a fájl elérési útja. A fájlnévnek perjellel kell kezdődnie. Ez jelzi, hogy a fájl gyökere a hosztnévben van megadva. A következő konstruktor egy portszámmal több paramétert tartalmaz az előzőhöz képest:

URL gamelan = new URL("http", "www.gamelan.com", 80,
                      "pages/Gamelan.network.html");

Ez egy URL objektumot csinál a következő URL-nek:

http://www.gamelan.com:80/pages/Gamelan.network.html[/codefilter_code]

Ha a fenti konstruktorok egyikével hozunk létre URL objektumot, a toString vagy toExternalForm paranccsal létrehozhatunk egy sztringet, amely tartalmazza a teljes URL címet.

MalformedURLException

A konstruktorok mindegyike MalformedURLException kivételt ad vissza, ha valamelyik paraméter null, vagy ismeretlen a protokoll. Ezt úgy tudjuk lekezelni, ha a konstruktort try/catch blokkba rakjuk, mit a következő kódban:

try {
    URL myURL = new URL(. . .)
} catch (MalformedURLException e) {
    . . .
        // Kivételkezelő kód
    . . .
}

Megjegyzés: Az URL objektumok egyszer írhatóak. Miután létrehoztunk egyet, nem lehet megváltoztatni az attribútumait (protokoll, hosztnév, fájlnév vagy portszám). Érdemes azt is megemlíteni, hogy az URL objektumok – hasonlóan a korábbi File objektumokhoz – a létrejöttükkor nem ellenőrzik az URL elérhetőségét, érvényességét stb., mivel az URL-nek egyenlőre csak egy logikai reprezentációja.

22.2.2 URL elemzés

Az URL osztály több metódussal szolgál, amellyel kérdéseket tehetünk fel az URL objektumoknak. Egy URL-től megkaphatja a protokollt, a hoszt nevét, a port számát és a fájlnevet az alábbi metódusokat használva:

  • getProtocol: Visszaadja az URL protokoll azonosító komponensét.
  • getHost: Visszaadja az URL hoszt név komponensét.
  • getPort: Visszaadja az URL port szám komponensét. A getPort metódus egy egészet ad vissza, ez a port szám. Ha a port nincs beállítva, akkor -1-et ad.
  • getFile: Visszaadja az URL fájlnév komponensét.
  • getRef: Visszaadja az URL hivatkozás komponensét.

Megjegyzés: Ne felejtse el, hogy egyes URL címek nem tartalmazzák ezeket a komponenseket. Az URL osztály azért nyújtja ezeket a metódusokat, mert a HTTP URL-ek és a leggyakrabban használt URL-ek tartalmazni szokták. Az URL osztály némiképp HTTP-centrikus.

Ezeket a getXXX metódusokat arra használhatja, hogy információt kapjon a URL-ről, tekintet nélkül a konstruktorra, amit az URL objektum elkészítésére használt.

Az URL osztály a metódusokkal együtt megszabadít az URL-ek állandó újraelemzésétől. Ha adott egy tetszés szerinti URL String, csak készítenünk kell egy URL objektumot, és meghívni valamelyik metódusát a szükséges információkért. Ez a kis példaprogram készít egy URL-t egy sztringből, és ezután az URL objektum metódusait használva elemzi az URL-t:

import java.net.*;
import java.io.*;
public class ParseURL {
    public static void main(String[] args) throws Exception {
        URL aURL = new URL("http://java.sun.com:80/docs/books/"
                          + "tutorial/index.html#DOWNLOADING");
        System.out.println("protocol = " + aURL.getProtocol());
        System.out.println("host = " + aURL.getHost());
        System.out.println("filename = " + aURL.getFile());
        System.out.println("port = " + aURL.getPort());
        System.out.println("ref = " + aURL.getRef());
    }
}

Ez a program kimenete:

protocol = http
host = java.sun.com
filename = /docs/books/tutorial/index.html
port = 80
ref = DOWNLOADING

22.2.3 Közvetlen olvasás URL-ből

Miután sikeresen készítettünk egy URL-t, az URL openStream metódusát meghívva kap egy adatfolyamot, amiből kiolvashatja az URL tartalmát. Az openStream metódus visszatérési értéke egy java.io.InputStream objektum, így olyan könnyű az URL-ből olvasni, mint egy tetszőleges állományból.

A következő kis program az openStream használatával kap egy bemenő folyamot a http://www.yahoo.com/ URL-re. Ezután nyit egy BufferedReader-t, ahonnan az URL tartalmát olvassa. Minden beolvasott sort átmásol a szabványos kimenetre:

import java.net.*;
import java.io.*;
public class URLReader {
    public static void main(String[] args) throws Exception {
    URL yahoo = new URL("http://www.yahoo.com/");
    BufferedReader in = new BufferedReader(
                new InputStreamReader(
                yahoo.openStream()));
    String inputLine;
    while ((inputLine = in.readLine()) != null)
        System.out.println(inputLine);
    in.close();
    }
}

Amikor futtatjuk a programot, láthatjuk a parancs ablakában görgetve a HTML elemeket és a szöveges tartalmat a http://www.yahoo.com/ címen található HTML fájlból. Esetleg a program leállhat kivétellel. Ha a utóbbi esemény bekövetkezik, a programunkban be kell állítanunk a proxyt, hogy a program megtalálhassa a Yahoo szervert.

22.2.4 Csatlakozás egy URL-hez

Miután sikeresen készítettünk egy URL objektumot, meghívhatjuk az URL objektum openConnection metódusát, hogy csatlakoztassuk. Amikor kapcsolódunk egy URL-hez, a hálózaton keresztül inicializálunk egy kommunikációs kapcsolatot a Java programja és az URL között. Például, nyithatunk egy kapcsolatot a Yahoo oldalra az alábbi kóddal:

try {
    URL yahoo = new URL("http://www.yahoo.com/");
    URLConnection yahooConnection = yahoo.openConnection();
} catch (MalformedURLException e) { // new URL() failed
    . . .
} catch (IOException e) {           // openConnection() failed
    . . .
}

Ha lehetséges, az openConnection metódus készít egy új URLConnection-t, inicializálja, csatlakozik az URL-hez, és visszatér az URLConnection objektummal. Ha valami nem megfelelő – például, a Yahoo szerver nem üzemel –, akkor az openConnection metódus egy IOException-t dob.

Miután sikeresen csatlakoztunk az URL-hez, írhatunk a csatlakozáshoz vagy olvashatunk róla az URLConnection objektum használatával.

Ha sikeresen használtuk az openConnection-t, hogy kommunikációt kezdeményezzen egy URL-lel, akkor van egy URLConnection objektumhivatkozásunk. Az URLConnection egy HTTP-centrikus osztály; ennek sok metódusa csak akkor hasznos, ha HTTP URL-ekkel dolgozik. Azonban a legtöbb URL protokoll megengedi, hogy olvasson és írjon a kapcsolatra.

Olvasás egy URLConnection-ról

Az alábbi program azonos funkciót hajt végre, mint az URLReader program. De ahelyett, hogy egy bemenő folyamot kapna közvetlenül az URL-ből, ez a program határozottan nyit egy kapcsolatot egy URL-hez, és egy bemenő folyamot kap a kapcsolatból. Ekkor, mint az URLReader, ez a program készít egy BufferedReader-t a bemenő folyamon, és onnan olvas. A félkövér szakaszok eltérőek az előző és a mostani példákban.

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

public class URLConnectionReader {
    public static void main(String[] args) throws Exception {
        URL yahoo = new URL("http://www.yahoo.com/");
        URLConnection yc = yahoo.openConnection();
        BufferedReader in = new BufferedReader(
                                new InputStreamReader(
                                yc.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null)
            System.out.println(inputLine);
        in.close();
    }
}

A program kimenete megegyezik az előző kimenettel. Használhatja mind a két módszer az URL-ből olvasásra. Azonban az URLConnection-ból olvasás sokkal használhatóbb lehet, mert az URLConnection objektumot használhatja más feladatokra is (például az URL-be írás) egy időben.

Még egyszer, ha a program leáll, vagy hibaüzenetet lát, be kell állítani a proxyt, hogy a program megtalálhassa a Yahoo szervert.

URLConnection-ba írás

Sok HTML lap tartalmaz űrlapokat – szöveg mezőket és más GUI objektumokat –, hogy beküldje a kitöltött adatokat a szerverre. Miután begépelte a szükséges információkat és elküldi a kérést egy gomb lenyomásával, a böngészőnk adatokat ír az URL-re a hálózaton keresztül. A szerver fogadja az adatokat, feldolgozza és visszaküld egy választ, általában egy új HTML oldal formájában.

Sok szkript használja a POST metódust a kliens adatainak továbbítására. A szerver-oldali szkriptek a POST metódust a bemenetük olvasására használják.

Egy Java program szintén kommunikálhat a szerver oldalon futó szkriptekkel. Egyszerűen lehet írni egy URL-be, így küldve adatokat a szerverre. Ezt a következő lépésekkel tudjuk megtenni:

  • Készítünk egy URL-t.
  • Nyitunk egy kapcsolatot az URL-hez.
  • Beállítjuk a kimenő képességet az URLConnection-on.
  • Kapunk egy kimenő folyamot. Ez a kimenő folyam összekapcsolt a szkript bemenő folyamával a szerveren.
  • Írunk a kimenő folyamba.
  • Bezárjuk a kimenő folyamot.

22.3 Socketek kezelése

A korábbi példák a kliens és szerver közötti magas szintű kommunikáció lehetőségeit mutatták be. Gyakran van olyan szituáció, amikor a magas szintű megközelítés nem megfelelő. Ekkor alacsonyabb szintű, úgynevezett socket alapú kommunikációra van szükség.

22.3.1 Mi az a socket?

Normális esetben a szerver egy speciális számítógépen fut és van egy socket-je, ami egy speciális port számra van kötve. A szerver várakozik, figyeli a socket-et hogy van-e felkérés egy klienstől a kapcsolódásra.

A kliens oldalon: A kliens ismeri annak a számítógépnek a hosztnevét, amelyiken a szerver fut, és annak a portnak a számát, amelyiken keresztül a szerver kapcsolódva van. A kapcsolatra való felkéréshez a kliensnek érintkeznie kell a szerverrel a szerver gépén és port-ján.

Connection Request

Ha minden jól megy, a szerver elfogadja a kapcsolatot. Az elfogadás során, a szerver egy új socket porthoz kapcsolódik. Kell egy új socket (és természetesen egy különböző port szám is), ezért folytatódik a figyelés az eredeti socket-en a kapcsolatkérésre, amíg a kliensnek kapcsolódnia kell.

Server-Client Conncection

A kliens oldalon, ha a kapcsolat elfogadásra került, a socket sikeresen létrejött, és a kliens használni tudja a socket-et a szerverrel való kommunikálásra.

Megjegyzés: a kliens oldali socket nincs összekötve azzal a port számmal, amit a szerverrel való kapcsolattartásra használ. A kliens a helyi kijelölt port számmal azonosítható azon a gépen, amin fut.
A kliens és a szerver kapcsolatot tud létrehozni a socket-jeik által írásra, vagy olvasásra.

Definíció: A socket egy végpontja egy kétvégű kommunikációs hálózatnak, amin két program fut. A socket egy port számhoz van kötve, ezért a TCP réteg azonosítani tudja a kérést, amit ahhoz kértek, hogy elküldhessék az adatot.

A java.net csomag a tartalmaz egy Socket osztályt, ami alkalmas egy kétirányú kapcsolat egyik oldalának vezérlésére egy, a hálózaton lévő másik program felé. Ezen kívül a java.net tartalmazza a ServerSocket osztályt, amely figyel és elfogadja a kapcsolatot a kliensektől.

Ha a webhez akarunk kapcsolódni, az URL osztály és a kapcsolódó osztályok (URLConnection, URLEncoder) talán alkalmasabbak, mint a Socket osztály. Valójában az URL viszonylag magas szintű kapcsolatot teremt a webbel, és használja a socket-eket.

22.3.2 Olvasás és írás a socket-ről

Nézzünk egy egyszerű példát arra, hogy hogyan lehet kiépíteni egy kapcsolatot a szerver programmal a Socket osztályt használva, azután megnézzük, hogy hogyan tud a kliens adatot küldeni és fogadni a szervertől a socket-en keresztül.

A példaprogram része az EchoClient, ami össze van kötve az echo szerverrel. Az echo szerver elég egyszerűen tud adatot fogadni a klienstől és választ küldeni rá. Az echo szerver egy jól ismert kiszolgáló, amit a kliens a 7-es port-on keresztül tud elérni.

Az EchoClient létrehoz egy socket-et azzal, hogy kapcsolódik az echo szerverhez. Ez beolvas a felhasználótól egy sort, elküldi az echo szervernek a socket-en keresztül. A szerver ezen keresztül válaszol a kliensnek. A kliens program olvassa ezt, és kiírja az adatot, amit visszaküldött neki a szerver:

import java.io.*;
import java.net.*;
public class EchoClient {
    public static void main(String[] args) throws IOException {        Socket echoSocket = null;
        PrintWriter out = null;
        BufferedReader in = null;
        try {
            echoSocket = new Socket("taranis", 7);
            out = new PrintWriter(echoSocket.getOutputStream(),
                                  true);
            in = new BufferedReader(new InputStreamReader(
                                 echoSocket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println(
                "Az alábbi host nem ismert: taranis.");
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for "
                              + "Kapcsolódás ehhez: taranis.");
            System.exit(1);
        }
    BufferedReader stdIn = new BufferedReader(
                            new InputStreamReader(System.in));
    String userInput;
    while ((userInput = stdIn.readLine()) != null) {
        out.println(userInput);
        System.out.println("echo: " + in.readLine());
    }

    out.close();
    in.close();
    stdIn.close();
    echoSocket.close();
    }
}

Az EchoClient olvasni és írni is tud a socket-ről azáltal, hogy átküld és átvesz adatot az echo szervertől.

Nézzük a program érdekesebb részeit. A main metódus try blokkjában szereplő sorok kiépítik a kapcsolatot a socket-en keresztül a kliens és a szerver között, és megnyitják a PrintWriter-t és a BufferedReader-t a socket-en.

echoSocket = new Socket("taranis", 7);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
                             echoSocket.getInputStream()));

Sorrendben az első rész létrehozza az új Socket objektumot, és nevet ad neki: echoSocket. A Socket konstruktor használata igényli annak a gépnek a nevét és a port-jának a számát, amelyikkel a kapcsolatot létre akarjuk hozni. A példa program a taranis host nevet használja. Ez a helyi hálózatunk virtuális gépének a neve. Mikor futtatjuk a programunkat, akkor saját szerver gépünk host neve kerüljön ide. A 7-es porton figyel az echo szerver.

A második sor összekapcsolja a Socket kimenetét és a PrintWriter-t. A harmadik sor hasonló ehhez, összekapcsolja a Socket bemenetét és a BufferedReader-t. A példa Unicode karaktereket tud írni a socket-en át.

Az EchoClient-nek az adatok socket-en való elküldéséhez egyszerűen a PrintWriter-hez kell írnia. Ahhoz, hogy megkapja a szerver válaszát, olvasnia kell a BufferedReader-ről. A program hátralevő részét ez teszi ki.

A while ciklus a program következő érdekes része. A ciklus beolvas egy sort egy bizonyos idő alatt a szabványos bementről, és azonnal elküldi azt a szervernek a PrintWriter-be való írással, ami a sockethez kapcsolódik:

String userInput;
while ((userInput = stdIn.readLine()) != null) {
    out.println(userInput);
    System.out.println("echo: " + in.readLine());
}

A while ciklus utolsó sorában beolvas egy sor szöveget a BufferedReader-ről, ami a socket-hez kapcsolódik. A readLine metódus addig vár, amíg a szerver válaszol az információra az EchoClient-nek. Mikor a readLine válaszol, az EchoClient kiírja a szöveget a szabványos kimenetre.

A while ciklus addig tart, amíg a felhasználó be nem gépeli az utolsó karaktert. Vagyis az EchoClient olvas a felhasználó bemenetéről, majd elküldi ezt az echo szervernek, kap egy választ a szervertől, és utána kiírja azt, amíg az elér az utolsó karakterig. A while ciklus ekkor bezárul, és a program folytatódik, futtatja a kód következő négy sorát:

out.close();
in.close();
stdIn.close();
echoSocket.close();

A kód e sorai a takarítást végzik. A jó program mindig kitakarít maga után, és ez a program is ilyen. Ezek a részek bezárják az olvasót és az írót, ami a socket-hez kapcsolódik és a szabványos kimenetet és bemenetet is, ami a szerverhez kapcsolódik. A sorrend itt nagyon fontos. Be kell zárnunk minden folyamatot, ami a socket-hez kapcsolódik, mielőtt kikapcsoljuk magát a socket-et.

  • Socket megnyitása.
  • Kimeneti és bementi folyam megnyitása a socket-en.
  • Olvasás és írás a szerver protokollja szerint.
  • A folyamatok bezárása.
  • Socket bezárása.