Hálózatkezelés Javában

Kategória: Java standard könyvtárak.

A standard Java a java.net csomagban definiálja a hálózati kapcsolat felépítéséhez szükséges osztályokat, interfészeket, tehát nem kell használnunk külön könyvtárakat. Az alábbi példákat a https://cs.lmu.edu/~ray/notes/javanetexamples/ oldal alapján készítettem.

Olvasás az internetről

A Java haladó témák között szerepel egy internetről történő beolvasás példa. A hálózati kapcsolat lényege a Socket osztályban van megvalósítva. Egyetlen sort a következőképpen tudunk beolvasni, alkalmazva a Java 7 által nyújtott kivételkezelési egyszerűsítéseket:

import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
 
public class ClientExample {
    public static void main(String[] args) {
        try (Socket socket = new Socket("djxmmx.net", 17)) {
            try (Scanner in = new Scanner(socket.getInputStream())) {
                System.out.println("Server response: " + in.nextLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

A djxmmx.net oldal a 17-es porton véletlenszerű idézeteket küld, a példában ezt olvassuk ki.

Dátum szerver és kliens

Lássuk ennek párját, egy egyszerű szervert:

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
 
public class DateServer {
    public static void main(String[] args) {
        int port = 50000;
        try (ServerSocket listener = new ServerSocket(port)) {
            System.out.println("The date server is listening on port " + port);
            while (true) {
                try (Socket socket = listener.accept()) {
                    System.out.println("A client has connected.");
                    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                    out.println(new Date().toString());
                    out.close();
                    System.out.println("Connection ended.");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Ha elindítjuk, akkor többféle módon kipróbálhatjuk, pl. a putty nevű program segítségével (host: localhost, port: 50000, connection type: raw, close window on exit: never), vagy a curl segítéségével (curl localhost:50000). De írhatunk hozzá klienst is:

import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
 
public class DateClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 50000)) {
            try (Scanner in = new Scanner(socket.getInputStream())) {
                System.out.println(in.nextLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Kétirányú kommunikáció: nagybetűsítés

A fent megadott módon valójában a szerver is küldhet információt a kliensnek és a kliens is a szervernek. Először lássunk egy szerver példát, amely tetszőleges szöveget vár inputként, és a nagybetűsített változatát küldi vissza:

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
 
public class CapitalizeServer {
    public static void main(String[] args) {
        int port = 60000;
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("The capitalization server is running on port " + port);
            while (true) {
                try (Socket socket = serverSocket.accept()) {
                    System.out.println("A client has connected: " + socket);
                    try (Scanner socketScanner = new Scanner(socket.getInputStream())) {
                        PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
                        while (socketScanner.hasNextLine()) {
                            output.println(socketScanner.nextLine().toUpperCase());
                        }
                        output.close();
                    }
                    System.out.println("Connection closed: " + socket);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Próbáljuk ki putty segítségével: csatakozzunk a fent megadott módon, majd írjunk be tetszőleges szöveget.

A klienst is elkészíthetjük hozzá:

package nettest;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
 
public class CapitalizeClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 60000)) {
            System.out.println("Enter lines of text then Ctrl+D or Ctrl+C to quit");
            try (Scanner consoleRead = new Scanner(System.in)) {
                try (Scanner networkRead = new Scanner(socket.getInputStream())) {
                    var out = new PrintWriter(socket.getOutputStream(), true);
                    while (consoleRead.hasNextLine()) {
                        out.println(consoleRead.nextLine());
                        System.out.println(networkRead.nextLine());
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Többszálú kliens kiszolgálás

A fenti példában vegyünk észre valamit: egyszerre csak egy klienst tud kiszolgálni a szerver! Próbáljunk meg pl. a putty segítségével kétszer csatlakozni: az első fog sikerülni, a második pedig várakozni fog (be ugyan tudunk írni szöveget de választ nem kapunk). Ám ha kilépünk az elsőből, akkor a második is végrehajtódik. Fejlesszük tovább: a már bemutatott egyik többszálú megoldással a csatlakozáskor induljon egy új szál, és azonnal flytassa a következő kliens kiszolgálását!

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executors;
 
class Capitalizer implements Runnable {
    private Socket socket;
 
    public Capitalizer(Socket socket) {
        this.socket = socket;
    }
 
    @Override
    public void run() {
        System.out.println("Connected: " + socket);
        try (Scanner in = new Scanner(socket.getInputStream())) {
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            while (in.hasNextLine()) {
                out.println(in.nextLine().toUpperCase());
            }
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Disconnected: " + socket);
    }
}
 
public class CapitalizeServer {
    public static void main(String[] args) throws Exception {
        int port = 60000;
        try (var listener = new ServerSocket(port)) {
            System.out.println("The capitalization server is running on port " + port);
            var pool = Executors.newFixedThreadPool(3);
            while (true) {
                pool.execute(new Capitalizer(listener.accept()));
            }
        }
    }
}

A példában egyszerre 3 kliens tud kiszolgálni. Ez a valóságban lehet jóval nagyobb; a könnyebb tesztelhetőség érdekében vettük le háromra. Indítsunk párhuzamosan 3 putty terminált a megadott módon, és mindegyik konzolra írjunk szöveget. Ha mindent jól csináltunk, megkapjuk válaszul a nagybetűsített változatát a beírt szövegnek. Most indítsunk egy negyediket: a kliens elindul, a szöveget be tudjuk írni, de választ nem kapunk. Ha viszont az első 3háromból egyet bezárunk, a nagyedik automatikusan szóhoz jut.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License