Lab - Aplikacje TCP-IP
TCP (Transmission Control Protocol) to protokół komunikacyjny zorientowany na połączenie, który zapewnia niezawodne, uporządkowane i bezbłędne dostarczanie danych między dwoma hostami. Dzięki mechanizmom kontroli błędów i retransmisji TCP jest podstawą działania wielu aplikacji sieciowych, takich jak przeglądarki internetowe, poczta elektroniczna czy transfer plików.
W języku Java do tworzenia połączeń TCP/IP wykorzystywane są głównie klasy:
Socket– dla klienta,ServerSocket– dla serwera.
Adresacja połączeń
Aby dostarczać bezbłędnie pakiety do odpowiedniego hosta wymagana jest odpowiednia adresacja. W tym celu w języku Java można wykorzystać klasę abstrakcyjną InetAddress, Która służy reprezentowania adresów IP i nazw hostów. Umożliwia m.in. wyszukiwanie adresów IP dla nazw domen, sprawdzanie dostępności hosta czy pobieranie informacji o lokalnym komputerze.
Do czego można wykorzystać InetAddress
Odnajdywanie adresów IP hostów lub nazw hostów po adresie IP.
InetAddress address = InetAddress.getByName("www.google.com"); System.out.println("Adres IP: " + address.getHostAddress());lub
InetAddress address = InetAddress.getByAddress(new byte[]{(byte)142, (byte)250, (byte)180, (byte)78}); System.out.println("Nazwa Hosta: " + address.getHostName());Pobieranie informacji o lokalnym urządzeniu.
InetAddress local = InetAddress.getLocalHost(); System.out.println("Lokalny host: " + local.getHostName()); System.out.println("Adres IP: " + local.getHostAddress());Sprawdzenie dostępności hosta (ping).
InetAddress google = InetAddress.getByName("www.google.com"); boolean reachable = google.isReachable(3000); // 3000 ms System.out.println("Czy host osiągalny? " + reachable);Obsługa adresów IPv4 i IPv6
InetAddress[] addresses = InetAddress.getAllByName("example.com"); for (InetAddress addr : addresses) { System.out.println(addr); }Integracja z klasami
SocketiSocketServerInetAddress serverAddress = InetAddress.getByName("192.168.0.101"); Socket socket = new Socket(serverAddress, 1234)
Tworzenie aplikacji serwerowej
Podstawową klasą wykorzystaną do stworzenia instancji serwera jest klasa ServerSocket, dzięki tej klasie możemy utworzyć nasłuchiwanie na połączenia przychodzące od klientów na określonym porcie i akceptować połączenia.
Przykład utworzenia instancji serwera
import java.io.*;
import java.net.*;
public class SimpleServer {
public static void main(String[] args) {
int port = 1234; // numer portu
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Serwer nasłuchuje na porcie " + port);
Socket clientSocket = serverSocket.accept(); // oczekiwanie na klienta
System.out.println("Połączono z klientem: " + clientSocket.getInetAddress());
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String message = in.readLine(); // odbiór wiadomości od klienta
System.out.println("Otrzymano: " + message);
out.println("Witaj kliencie! Otrzymałem: " + message); // odpowiedź serwera
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}Tworzenia aplikacja klienta
W sytuacji kiedy wymagane jest połączenie z innym procesem lub innym urządzeniem pełniącym rolę serwera, należy skorzystać z klasy Socket, dzięki której możemy nawiązać połączenie z instancją serwera na określonym adresie i porcie.
Przykład instancji klienta
import java.io.*;
import java.net.*;
public class SimpleClient {
public static void main(String[] args) {
String host = "localhost"; // adres serwera
int port = 1234; // port serwera
try (Socket socket = new Socket(host, port)) {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("Cześć, tu klient!"); // wysłanie wiadomości
String response = in.readLine(); // odbiór odpowiedzi
System.out.println("Odpowiedź serwera: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}Powyższe dwa przykłady kodu przedstawiają aplikacje klienta i serwera działające tylko na jedno połączenie. Po zakończeniu połączenia aplikacje kończą pracę. Aplikacje wykonują nie szyfrowane połączenie, aby instancja serwera działała lepiej należy ją zmodyfikować dodając wielowątkowość, tak aby każde połączenie było uruchamiane w osobnym wątku. Takie rozwiązanie pozwala na większą liczbę połączeń oraz większą możliwość monitorowania instancji serwerowej.
Zadania
Zaimplementuj prosty chat – klient wysyła wiadomość, a serwer ją odsyła w zmodyfikowanej formie (np. wielkimi literami).
Rozszerz klienta o możliwość wysyłania kilku wiadomości do serwera. (wymagań wiedza z tematu 1)
Rozszerz aplikację z zadania 2 o obsługę wielu połączeń jednocześnie, stwórz rozwiązanie, w którym każde połączenie będzie obsługiwane w osobnym wątku. Zaproponuj rozwiązanie za pomocą, którego będzie możliwość monitorowania ile połączeń jest aktywnych.
Stwórz mechanizm do zarządzania połączeniami z zadania 3, w taki sposób aby można było sprawdzić ile jest połączonych użytkowników i wyświetlić informacje o nim typu nazwa hosta czy adres IP skorzystaj z metod
getInetAddress().getHostAddress()czygetInetAddress().getHostName()
Last updated