~~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|}}