====== 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)