~~NOCACHE~~
~~REVEAL theme=simple&disableLayout=0&transition=none&controls=1&show_progress_bar=1&build_all_lists=0&show_image_borders=0&horizontal_slide_level=2&enlarge_vertical_slide_headers=0&show_slide_details=1&open_in_new_window=1&size=1024x768~~
====== Programowanie zorientowane sieciowo ======
===== Gniazda i HTTP =====
{{ 157_1_gniazda.jpg |}}
Programowanie oparte na gniazdach (sockets)
* komunikacja klient-serwera oparta na gniazdach z wykorzystaniem TCP, UDP lub innych protokołów
* po obu stronach tworzymy gniazda, powiązane z adresami IP i portami
* komunikacja dwukierunkowa za pomocą strumieni wejścia/wyjścia
Przetwarzanie adresów URL (HTTP)
* praca z adresami URL, pobieranie danych z sieci, obsługa protokołów takich jak HTTP, HTTPS, FTP
* żądania HTTP, obsługa odpowiedzi, nagłówków, itp.
===== Protokoły TCP i UDP =====
**TCP** - połączeniowy, niezawodny, strumieniowy, kontrola kolejności
* wykorzystuje protokół IP do odbierania i wysyłania danych, dzieląc przesyłane dane na fragmenty, jeśli jest to potrzebne
* API, czat, transfer plików, HTTP, HTTPS, SMTP, itp.
**UDP** - bezpołączeniowy, szybki, datagramowy, brak retransmisji
* szybsza transmisja bez dodatkowych narzutów, ale bez gwarancji dostarczenia, kolejności czy integralności danych
* gry, telemetria, VoIP, wykrywanie usług, rozgłaszanie, itp.
===== Adresacja IP i porty =====
* IPv4: ''192.168.1.10'', IPv6: ''2001:db8::1''
* Nazwy domenowe: ''example.com'' -> rozwiązywane na adresy IP przez DNS
* Porty znane: 0-1023 (HTTP 80, HTTPS 443) - zarezerwowane dla systemu i usług
* Porty zarejestrowane: 1024-49151 - aplikacje użytkowe
* Porty dynamiczne: 49152-65535 - tymczasowe, często używane przez klientów
* ''localhost'', ''127.0.0.1'' - adres hosta lokalnego
===== Java i sieć - podstawowe pakiety =====
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/package-summary.html|java.net]] - gniazda, URL, URI, DNS
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/package-summary.html|java.net.http]] (Java 11+) - nowoczesny klient HTTP
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/io/package-summary.html|java.io]] - strumienie i serializacja danych
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/package-summary.html|java.nio]] / [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/channels/package-summary.html|java.nio.channels]] - I/O nieblokujące
===== Najważniejsze klasy i interfejsy =====
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/InetAddress.html|InetAddress]] - adresy i DNS
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/Socket.html|Socket]], [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/ServerSocket.html|ServerSocket]] - TCP klient/serwer
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/DatagramSocket.html|DatagramSocket]], [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/DatagramPacket.html|DatagramPacket]] - UDP nadawca/odbiorca
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URL.html|URL]], [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URLConnection.html|URLConnection]], [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/HttpURLConnection.html|HttpURLConnection]] - klasyczne HTTP
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/HttpClient.html|HttpClient]], [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/HttpRequest.html|HttpRequest]], [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/HttpResponse.html|HttpResponse]] - nowoczesny HTTP
===== InetAddress =====
[[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/InetAddress.html|InetAddress]] - reprezentuje adres IP i nazwę hosta. Kluczowe metody:
* ''getByName(String host)'' - rozwiązywanie DNS
* ''getByAddress(byte[] addr)'' - tworzenie z surowych bajtów
* ''getLocalHost()'' - adres hosta lokalnego
* ''getHostAddress()'' i ''getHostName()''
InetAddress local = InetAddress.getLocalHost();
System.out.println(local.getHostName());
System.out.println(local.getHostAddress());
InetAddress google = InetAddress.getByName("www.google.com");
System.out.println(google.getHostAddress());
===== Komunikacja TCP oparta na gniazdach (sockets) =====
* serwer tworzy gniazdo (''ServerSocket'') na konkretnym porcie
* serwer rozpoczyna nasłuch (''accept()'')
* klient, znając adres i port serwera, tworzy gniazdo (''Socket'') i łączy się z serwerem
* po zaakceptowaniu połączenia przez serwer, obie strony mają otwarte gniazda do komunikacji
* komunikacja odbywa się za pomocą strumieni wejścia/wyjścia
* po zakończeniu komunikacji, gniazda powinny być zamknięte, aby zwolnić zasoby systemowe
{{ 158_1_socket.jpg?800 |}}
===== Komunikacja TCP - Serwer =====
[[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/ServerSocket.html|ServerSocket]] tworzy gniazdo serwera TCP. Konstruktorzy:
* ''ServerSocket(int port)'' - nasłuch na porcie (''IOException'' jeśli port zajęty)
* ''ServerSocket(int port, int backlog)'' - nasłuch z określoną liczbą oczekujących połączeń
* ''ServerSocket(int port, int backlog, InetAddress bindAddr)'' - nasłuch z określonym adresem (gdy serwer ma wiele interfejsów sieciowych)
Kluczowe metody:
* ''accept()'' - czeka na klienta i zwraca ''Socket'' (''SocketTimeoutException'' jeśli timeout)
* ''bind(SocketAddress endpoint)'' - wiąże z adresem i portem (jeśli nie podano w konstruktorze)
* ''setSoTimeout(int timeout)'' - timeout dla ''accept()''
* ''getLocalPort()'' - numer portu lokalnego
* ''close()'' - zamknięcie serwera (//try-with-resources// lub ręcznie)
===== Komunikacja TCP - Klient =====
[[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/Socket.html|Socket]] tworzy gniazdo klienta TCP
* ''Socket(String host, int port)'' - łączy z serwerem na adresie ''host'' i porcie ''port''
* ''Socket(InetAddress host, int port)'' - łączy z serwerem na adresie ''host'' i porcie ''port''
* ''Socket()'' - tworzy gniazdo bez połączenia
* ''Socket(String host, int port, InetAddress localAddr, int localPort)'' - łączy z serwerem i wiąże z lokalnym adresem i portem
Metody:
* ''connect(SocketAddress host, int timeout)'' - łączy z serwerem (jeśli nie podano w konstruktorze)
* ''getInputStream()'' / ''getOutputStream()'' - strumienie do komunikacji
* ''getInetAddress()'', ''getPort()'', ''getLocalPort()'', ''getRemoteSocketAddress()'' - informacje o połączeniu
* ''close()'' - zamyka gniazdo
===== Przykład: prosty serwer TCP =====
ServerSocket server = new ServerSocket(5000);
Socket client = server.accept();
// strumień wejściowy (tekstowy) do komunikacji z klientem
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String line = in.readLine();
// strumień wyjściowy (tekstowy) do komunikacji z klientem
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
out.println("ECHO: " + line);
===== Przykład: prosty klient TCP =====
try (Socket socket = new Socket("127.0.0.1", 5000);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
out.println("ping");
String response = in.readLine();
System.out.println("Odpowiedz z serwera: " + response);
}
===== Gniazda bezpołączeniowe (UDP) =====
UDP stosujemy, gdy nie jest potrzebna niezawodność i kolejność, a liczy się szybkość i niskie opóźnienia.
* serwer i klient nie tworzą trwałego połączenia, a komunikacja odbywa się za pomocą pojedynczych pakietów (datagramów)
* każdy pakiet jest niezależny, może być dostarczony w dowolnej kolejności, może zostać zgubiony lub zduplikowany
{{167_1_udp.png|}}
===== Gniazda bezpołączeniowe (UDP) =====
[[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/DatagramSocket.html|DatagramSocket]] tworzy gniazdo UDP:
* ''DatagramSocket()'' - tworzy gniazdo i wiąże je z wolnym portem
* ''DatagramSocket(int port)'' - wiąże z konkretnym portem
* ''DatagramSocket(int port, InetAddress address)'' - wiąże z portem i adresem
* Metody do komunikacji: \\ ''send(DatagramPacket dp)'', ''receive(DatagramPacket dp)''
[[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/DatagramPacket.html|DatagramPacket]] - pakiet danych UDP:
* ''DatagramPacket(byte[] barr, int length)'' - utworzenie pakietu do odbioru danych
* ''DatagramPacket(byte[] barr, int length, InetAddress address, int port)'' - utworzenie pakietu do wysłania danych do konkretnego adresu i portu
===== Przykład: UDP nadawca =====
try (DatagramSocket sender = new DatagramSocket()) {
byte[] data = "hello udp".getBytes(StandardCharsets.UTF_8);
DatagramPacket packet = new DatagramPacket(
data,
data.length,
InetAddress.getByName("127.0.0.1"),
6000
);
sender.send(packet);
}
===== Przykład: UDP odbiorca =====
try (DatagramSocket receiver = new DatagramSocket(6000)) {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
receiver.receive(packet);
String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
System.out.println("UDP: " + msg);
}
===== URL, URI, URLConnection =====
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URI.html|URI]] - identyfikator zasobu (często bez pobierania danych)
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URL.html|URL]] - lokalizacja zasobu i możliwość otwarcia połączenia
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URLConnection.html|URLConnection]] - bazowy interfejs pracy na połączeniu
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/HttpURLConnection.html|HttpURLConnection]] - klasyczny klient HTTP (przed Java 11)
URL url = new URL("https://example.com/api/users?page=1");
System.out.println(url.getProtocol()); // https
System.out.println(url.getHost()); // example.com
System.out.println(url.getPath()); // /api/users
System.out.println(url.getQuery()); // page=1
System.out.println(url.getPort()); // -1 (domyślny port)
System.out.println(url.getDefaultPort()); // 443
System.out.println(url.getFile()); // /api/users?page=1
System.out.println(url.getRef()); // null (część po #)
System.out.println(url.getAuthority()); // example.com
===== URLConnection - pobieranie danych =====
* Metoda [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URL.html#openConnection()|openConnection()]] na obiekcie [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URL.html|URL]] zwraca instancję [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URLConnection.html|URLConnection]], która pozwala na interakcję z zasobem sieciowym
* Możemy użyć [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URLConnection.html|URLConnection]] do pobierania danych, odczytywania nagłówków, wysyłania danych (w przypadku HTTP) i innych operacji sieciowych
URL url = new URL("https://api.github.com");
URLConnection conn = url.openConnection();
try (InputStream in = conn.getInputStream()) {
String content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
System.out.println(content);
}
===== URLConnection - najważniejsze metody =====
* ''getContent()'' - zwraca zawartość połączenia z URL
* ''getContent(Class[] classes)'' - próbuje zwrócić zawartość połączenia jako jeden z typów podanych w parametrze classes
* ''getContentEncoding()'' - zwraca zawartość nagłówka content-encoding
* ''getContentLength()'' - zwraca zawartość nagłówka content-length
* ''getContentType()'' - zwraca zawartość nagłówka content-type
* ''getLastModified()'' - zwraca zawartość nagłówka last-modified
* ''getExpiration()'' - zwraca zawartość nagłówka expires
* ''getInputStream()'' - zwraca strumień wejściowy z URL (pozwala na czytanie)
* ''getOutputStream()'' - zwraca strumień wyjściowy z URL (pozwala na wysyłanie)
* ''getURL()'' - zwraca adres URL do którego podłączony jest obiekt klasy URLConnection
===== HttpURLConnection - prosty klient HTTP =====
[[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/HttpURLConnection.html|HttpURLConnection]] to podklasa [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/URLConnection.html|URLConnection]], która dodaje funkcje specyficzne dla protokołu HTTP, takie jak obsługa metod HTTP, nagłówków, kodów statusu i innych aspektów komunikacji HTTP.
Metody:
* ''setRequestMethod(String method)'' - GET, POST, itp.
* ''setRequestProperty(String key, String value)'' - nagłówki
* ''getResponseCode()'' - kod statusu HTTP
* ''getInputStream()'' - strumień odpowiedzi (dla 2xx)
* ''getContent()'' - zawartość odpowiedzi
* ''getErrorStream()'' - strumień błędu (dla 4xx/5xx)
* ''disconnect()'' - zamyka połączenie
===== Nowoczesny HTTP Client (Java 11+) =====
[[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/package-summary.html|java.net.http]] to nowoczesny klient HTTP wprowadzony w Javie 11, który oferuje bardziej elastyczne i wydajne API do pracy z protokołem HTTP/1.1 i HTTP/2
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/HttpClient.html|HttpClient]] - główna klasa do tworzenia i konfigurowania klienta HTTP
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/HttpRequest.html|HttpRequest]] - żądanie HTTP, pozwala na ustawienie metody, URI, nagłówków i ciała
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/HttpResponse.html|HttpResponse]] - odpowiedź HTTP, zawiera status, nagłówki i ciało odpowiedzi
* Obsługa zarówno synchroniczna (''send''), jak i asynchroniczna (''sendAsync'')
* metody wytwórcze (''builder()'') do łatwego tworzenia żądań i konfiguracji klienta
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.github.com"))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
===== Prosty serwer HTTP w Java =====
* Lekki serwer: ''com.sun.net.httpserver.HttpServer''
* Dobre do testów, demo i lokalnych API
* Produkcyjnie: zwykle Spring Boot / Quarkus / Micronaut
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/hello", exchange -> {
String body = "{\"message\":\"hello\"}";
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=utf-8");
exchange.sendResponseHeaders(200, body.getBytes(StandardCharsets.UTF_8).length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(body.getBytes(StandardCharsets.UTF_8));
}
});
server.start();
===== Dokumentacja =====
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/package-summary.html|java.net package]]
* [[https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/package-summary.html|java.net.http package]]
* [[https://docs.oracle.com/en/java/javase/25/docs/api/jdk.httpserver/com/sun/net/httpserver/package-summary.html|JDK HttpServer]]
===== Zadanie 9: Komunikator =====
Stwórz prosty komunikator, który pozwala na bezpośrednią wymianę wiadomości tekstowych między dwiema aplikacjami korzystając z protokołu TCP.
* Jedna aplikacja będzie działać jako serwer, a druga jako klient.
* Serwer po uruchomieniu nasłuchuje na określonym porcie i czeka na połączenie od klienta.
* Klient po uruchomieniu łączy się z serwerem na określonym porcie.
* Po nawiązaniu połączenia, obie aplikacje powinny umożliwiać wysyłanie i odbieranie wiadomości w czasie rzeczywistym.
* Stwórz możliwie najprostszy interfejs graficzny umożliwiający wysyłanie wiadomości (pole tekstowe i przycisk "Wyślij") oraz wyświetlanie wiadomości przychodzących, wysłanych i komunikatów diagnostycznych. GUI może byc oparte na dowolnej technologii (AWT, Swing, JavaFX)
* Wystarczające jest aby aplikacja komunikowała się z inną instancją uruchomioną na tym samym komputerze (''localhost'').
Opcjonalnie:
* Dodaj możliwość komunikacji między różnymi komputerami w sieci lokalnej. Wymaga podania w aplikacji klienta adresu IP (i ewentualnie portu) serwera i przycisku "Połącz".
Przykładowe rozwiązanie:
{{zajecia:java_2026_1:komunikator_serwer.png?300|}} {{zajecia:java_2026_1:komunikator_klient.png?300|}}