====== Zajecia 10. - Obsluga sieci w Java - zadania do samodzielnego wykonania ====== ===== Organizacja ===== * Czas: 20-30 min * Forma: samodzielnie lub w parach * Zakres: od podstaw TCP/UDP do prostych uslug HTTP ===== Zadanie A (latwe): Klient TCP - kalkulator sumy ===== Wymagania: * Serwer TCP odbiera linie w formacie ''a+b'' (np. ''12+30'') * Serwer zwraca wynik jako tekst * Klient wysyla jedno dzialanie i wyswietla odpowiedz Wskazowki: * po stronie serwera uzyj ''split("\\+")'' * waliduj wejscie i obsluz bledny format * zamykaj zasoby przez ''try-with-resources'' Rozwiazanie (przykladowy serwer): try (ServerSocket server = new ServerSocket(5001)) { while (true) { try (Socket client = server.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(client.getOutputStream(), true)) { String expr = in.readLine(); String[] parts = expr.split("\\+"); if (parts.length != 2) { out.println("BLAD FORMATU"); continue; } int a = Integer.parseInt(parts[0].trim()); int b = Integer.parseInt(parts[1].trim()); out.println(a + b); } catch (Exception ex) { // obsluga pojedynczego klienta } } } ===== Zadanie B (latwe/srednie): UDP licznik wiadomosci ===== Wymagania: * Odbiorca UDP nasluchuje na porcie 6001 * Dla kazdego datagramu wypisuje tresc i numer kolejnosci * Po odebraniu ''STOP'' konczy dzialanie Wskazowki: * porownuj tekst po ''trim()'' * uzyj stalego bufora i nowego ''DatagramPacket'' na kazde ''receive'' Rozwiazanie (przykladowe): int counter = 0; try (DatagramSocket socket = new DatagramSocket(6001)) { byte[] buffer = new byte[1024]; while (true) { DatagramPacket packet = new DatagramPacket(buffer, buffer.length); socket.receive(packet); String text = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8).trim(); counter++; System.out.println(counter + ": " + text); if ("STOP".equalsIgnoreCase(text)) break; } } ===== Zadanie C (srednie): Klient HTTP - pobieranie JSON ===== Wymagania: * Pobierz dane z endpointu HTTP GET * Wypisz kod statusu i 3 wybrane pola z JSON (np. id, title, completed) * Dodaj obsluge timeout Wskazowki: * uzyj ''HttpClient'' i ''HttpRequest'' * do prostego demo mozesz parsowac tekstowo lub przez biblioteke JSON * endpoint testowy: ''https://jsonplaceholder.typicode.com/todos/1'' Rozwiazanie (przykladowe): HttpClient client = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(5)) .build(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://jsonplaceholder.typicode.com/todos/1")) .timeout(Duration.ofSeconds(5)) .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Status: " + response.statusCode()); System.out.println(response.body()); ===== Zadanie D (srednie+): Wielowatkowy czat TCP (wersja mini) ===== Wymagania: * Serwer akceptuje wielu klientow * Kazda wiadomosc klienta jest rozglaszana do pozostalych * Obsluz rozlaczenie klienta Wskazowki: * lista klientow: ''CopyOnWriteArrayList'' * kazdy klient w osobnym watku * przed broadcast usun nieaktywne polaczenia Rozwiazanie (szkic): static List clients = new CopyOnWriteArrayList<>(); void handle(Socket socket) { try (socket; BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { clients.add(out); String line; while ((line = in.readLine()) != null) { for (PrintWriter c : clients) { if (c != out) c.println(line); } } } catch (IOException ignored) { } finally { // usun writer klienta z listy } } ===== Zadanie E (trudniejsze): Mini REST API - notatki ===== Wymagania: * Serwer HTTP z endpointami: * ''GET /notes'' - lista notatek (JSON) * ''POST /notes'' - dodanie notatki (tekst) * Przechowywanie w pamieci (''List'') Wskazowki: * start: ''HttpServer.create(new InetSocketAddress(8081), 0)'' * dla ''POST'' odczytaj body z ''exchange.getRequestBody()'' * ustaw odpowiednie kody: 200, 201, 405 Rozwiazanie (szkic): List notes = Collections.synchronizedList(new ArrayList<>()); server.createContext("/notes", exchange -> { String method = exchange.getRequestMethod(); if ("GET".equalsIgnoreCase(method)) { String json = notes.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(",", "[", "]")); byte[] bytes = json.getBytes(StandardCharsets.UTF_8); exchange.sendResponseHeaders(200, bytes.length); try (OutputStream os = exchange.getResponseBody()) { os.write(bytes); } } else if ("POST".equalsIgnoreCase(method)) { String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8).trim(); notes.add(body); exchange.sendResponseHeaders(201, -1); } else { exchange.sendResponseHeaders(405, -1); } }); ===== Zadanie F (dla chetnych): HTTPS + naglowek autoryzacji ===== Wymagania: * Wyslij zapytanie HTTPS GET z naglowkiem ''Authorization: Bearer ...'' * Wypisz status i czas odpowiedzi * Dodaj retry do 3 prob dla bledow 5xx Wskazowki: * zmierz czas przez ''System.nanoTime()'' * token przekazuj z argumentu programu albo zmiennej srodowiskowej * nie loguj calego tokenu Rozwiazanie (fragment): long start = System.nanoTime(); HttpRequest req = HttpRequest.newBuilder() .uri(URI.create("https://example.com/api/me")) .header("Authorization", "Bearer " + token) .GET() .build(); HttpResponse res = client.send(req, HttpResponse.BodyHandlers.ofString()); long ms = (System.nanoTime() - start) / 1_000_000; System.out.println("Status=" + res.statusCode() + ", czas=" + ms + "ms"); ===== Kryteria oceny ===== * Dzialajaca komunikacja klient-serwer * Poprawna obsluga bledow i timeoutow * Czytelnosc kodu i podzial odpowiedzialnosci * Plus: watki, walidacja danych, sensowne logowanie ===== Proponowany dobor zadan na 20-30 min ===== * Grupa poczatkujaca: A + B * Grupa srednia: A + C + fragment D * Grupa zaawansowana: C + D lub E (+F dla chetnych)