From 8aae306704dd544bcf1e284b85e58eae964f88f1 Mon Sep 17 00:00:00 2001 From: Dimitrios Date: Mon, 13 Apr 2026 14:42:07 +0200 Subject: [PATCH] modify justfile (to start server with just server); improved Readme; modify server (log-output is now better structured); modify client --- README.md | 52 +++++++++++------- justfile | 4 ++ src/main/java/vs/SyslogClient.java | 35 +++++++------ src/main/java/vs/SyslogServer.java | 84 +++++++++++------------------- 4 files changed, 85 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 28fa698..f92bdd1 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,44 @@ -# Verteilte_Systeme +# PU 1: "Praktikum Service-Discovery" -Bearbeitung Prüfungsvorleistung für Verteilte Systeme +Dieses Projekt wurde von der **Gruppe D** entwickelt: +**Antoniadis Dimitrios, Dexheimer Fynn, Corina Schmitt** -# Syslog-Logging-System (RFC 5424) +Dieses Projekt implementiert einen Syslog-Server auf Basis von UDP gemäß dem RFC 5424 Standard. Es beinhaltet eine automatische Service-Discovery via Broadcast. -Dieses Projekt implementiert einen Syslog-Server und einen Test-Client auf Basis von UDP. Es beinhaltet eine automatische Service-Discovery. +> **Hinweis:** Um den Server zu testen, wird ein entsprechender Client benötigt. Das System setzt die installierten Technologien **Java**, **Maven** voraus. **Just** ist Optional. ## Projektstruktur & Klassen -* **`pom.xml`**: Die Maven-Konfigurationsdatei. Sie verwaltet Abhängigkeiten und die Java-Version. -* **`justfile`**: Automatisierungsskript für Windows (PowerShell) und Linux, um Befehle wie `just clean` oder `just exec` zu nutzen. +* **`pom.xml`**: Maven-Konfigurationsdatei für Abhängigkeiten und Build-Prozess. +* **`justfile`**: Automatisierungsskript für einfache Ausführung (`just server`). * **`vs.SyslogServer`**: Der Hauptdienst. Er startet zwei parallele Threads: - * **Syslog-Service**: Empfängt Log-Nachrichten auf Port 514. - * **Discovery-Service**: Antwortet auf Broadcast-Anfragen auf Port 8888. -* **`vs.SyslogClient`**: Test-Client, der den Server via Broadcast sucht und eine standardkonforme Nachricht sendet. -* **`vs.SyslogMessage`**: Repräsentiert eine Nachricht gemäß RFC 5424. -* **`vs.AsciiChars` / `vs.StructuredData`**: Hilfsklassen zur Validierung und Formatierung von Zeichenketten gemäß Spezifikation. + * **Syslog-Service**: Empfängt Log-Nachrichten auf Port 514, validiert die Länge und trennt Metadaten optisch vom Nachrichteninhalt. + * **Discovery-Service**: Antwortet auf Broadcast-Anfragen auf Port 8888, um Clients die Server-IP mitzuteilen. +* **`vs.SyslogMessage`**: Kernklasse zur Erzeugung/Repräsentation standardkonformer Nachrichten (inkl. Header, Zeitstempel und Structured Data). +* **`vs.AsciiChars` / `vs.StructuredData`**: Hilfsklassen zur Einhaltung der RFC-Spezifikationen. -## Funktionsablauf (Service Discovery) -1. **Broadcast**: Der Client sendet ein UDP-Paket an `255.255.255.255:8888`. -2. **Antwort**: Der Server empfängt den Broadcast und sendet ein leeres UDP-Paket an den Client zurück. -3. **Identifikation**: Der Client liest die IP-Adresse des Absenders aus dem Antwort-Paket aus. -4. **Logging**: Der Client sendet die eigentliche Syslog-Nachricht direkt an die ermittelte IP auf Port 514. +## Funktionsablauf (Service Discovery & Logging) + +1. **Broadcast**: Ein Client sendet ein UDP-Paket an die Broadcast-Adresse `255.255.255.255:8888`. +2. **Antwort**: Der Server empfängt den Suchruf und sendet ein Bestätigungs-Paket an den Client zurück. +3. **Identifikation**: Der Client extrahiert die IP-Adresse des Servers aus dem Antwort-Paket. +4. **Logging**: Der Client formatiert die Nachricht nach RFC 5424 und sendet sie direkt an den Server (Port 514). +5. **Verarbeitung**: Der Server empfängt das Datenpaket, validiert die Länge, entfernt das Byte Order Mark (BOM) und trennt die RFC-Metadaten optisch vom eigentlichen Nachrichteninhalt für eine strukturierte Konsolenausgabe. ## Ausführung -* Server starten: `just exec SyslogServer` -* Client starten: `just exec SyslogClient` -* Aufräumen: `just clean` \ No newline at end of file + +Stellen Sie sicher, dass **Java**, **Maven** und **Just** auf Ihrem System installiert sind. + +### 1. Konfiguration für Linux/macOS +Da das `justfile` standardmäßig für die PowerShell optimiert ist, passen Sie bei der Nutzung von Unix-basierten Systemen bitte die erste Zeile im `justfile` an: +* Ändern Sie `set shell := ["powershell.exe", "-c"]` zu `set shell := ["sh", "-c"]`. + +### 2. Wichtige Befehle +Nutzen Sie `just`, um die folgenden Aufgaben automatisiert auszuführen: + +* **Kompilieren**: `just compile` +* **Server starten**: `just server` +* **Projekt aufräumen**: `just clean` + +*Hinweis: Weitere Befehle für Tests oder die Javadoc-Generierung finden Sie direkt im `justfile`.* \ No newline at end of file diff --git a/justfile b/justfile index 15706c8..8e5f7af 100644 --- a/justfile +++ b/justfile @@ -4,6 +4,10 @@ set shell := ["powershell.exe", "-c"] default: mvn clean compile test +server: compile + mvn exec:java "-Dexec.mainClass=vs.SyslogServer" +client +args="": compile + mvn exec:java "-Dexec.mainClass=vs.SyslogClient" "-Dexec.args={{args}}" exec class +args="": compile mvn exec:java "-Dexec.mainClass=vs.{{class}}" "-Dexec.args={{args}}" clean: diff --git a/src/main/java/vs/SyslogClient.java b/src/main/java/vs/SyslogClient.java index 8dff648..a13ffe3 100644 --- a/src/main/java/vs/SyslogClient.java +++ b/src/main/java/vs/SyslogClient.java @@ -7,29 +7,33 @@ import java.nio.charset.StandardCharsets; public class SyslogClient { - private static final int PORT = 514; + private static final int SYSLOG_PORT = 514; + private static final int DISCOVERY_PORT = 8888; + public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(); socket.setBroadcast(true); - // Discovery + // 1. SERVICE DISCOVERY + System.out.println("[CLIENT] Suche Syslog-Server via Broadcast..."); byte[] discoverMsg = "DISCOVER".getBytes(); - DatagramPacket packet = new DatagramPacket( + DatagramPacket discoverPacket = new DatagramPacket( discoverMsg, discoverMsg.length, - InetAddress.getByName("255.255.255.255"), 8888 + InetAddress.getByName("255.255.255.255"), DISCOVERY_PORT ); - socket.send(packet); + socket.send(discoverPacket); - // Antwort empfangen + // Auf Antwort warten byte[] buffer = new byte[256]; DatagramPacket response = new DatagramPacket(buffer, buffer.length); socket.receive(response); - System.out.println("Server gefunden: " + response.getAddress()); + + InetAddress serverAddress = response.getAddress(); + System.out.println("[CLIENT] Server gefunden unter: " + serverAddress.getHostAddress()); - // ECHTE RFC 5424 Syslog-Nachricht aus AsciiChars & SyslogMessage - // args als massage, ansonsten default message - String text = (args.length > 0) ? String.join(" ", args): "Dies ist eine standardkonforme Testnachricht"; - + // 2. NACHRICHT ERSTELLEN + String text = (args.length > 0) ? String.join(" ", args) : "Standard-Testnachricht"; + SyslogMessage msg = new SyslogMessage( SyslogMessage.Facility.USER, SyslogMessage.Severity.INFORMATIONAL, @@ -41,19 +45,16 @@ public class SyslogClient { new SyslogMessage.TextMessage(text) ); - // Die Klasse wandelt alles in den perfekten String um (inklusive Zeitstempel) + // 3. SENDEN String logString = msg.toString(); - System.out.println("Sende generierten String: " + logString); - - // Nachricht als UTF-8 Bytes senden byte[] data = logString.getBytes(StandardCharsets.UTF_8); DatagramPacket syslogPacket = new DatagramPacket( - data, data.length, response.getAddress(), PORT + data, data.length, serverAddress, SYSLOG_PORT ); socket.send(syslogPacket); - System.out.println("Log gesendet!"); + System.out.println("[CLIENT] Nachricht gesendet: " + logString); socket.close(); } diff --git a/src/main/java/vs/SyslogServer.java b/src/main/java/vs/SyslogServer.java index df57486..0b3adee 100644 --- a/src/main/java/vs/SyslogServer.java +++ b/src/main/java/vs/SyslogServer.java @@ -3,106 +3,82 @@ package vs; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; -import java.net.InetAddress; import java.nio.charset.StandardCharsets; public class SyslogServer { private static final int SYSLOG_PORT = 514; private static final int DISCOVERY_PORT = 8888; - private static final int MAX_MESSAGE_LENGTH = 1024; // konservativ (UDP safe) + private static final int MAX_MESSAGE_LENGTH = 1024; public static void main(String[] args) { - System.out.println("Starting Syslog Server..."); - - // Thread für Syslog + System.out.println("=== Syslog Server Management ==="); + + // Startet den Syslog-Empfänger new Thread(() -> runSyslogServer()).start(); - // Thread für Discovery + // Startet den Discovery-Dienst new Thread(() -> runDiscoveryServer()).start(); } private static void runSyslogServer() { try (DatagramSocket socket = new DatagramSocket(SYSLOG_PORT)) { - // Puffergröße 2048 gemäß RFC 5424 Empfehlung. - // Ermöglicht den Empfang kompletter Netzwerkpakete (MTU), um zu lange - // Nachrichten aktiv zu erkennen und abzulehnen, statt sie nur abzuschneiden. byte[] buffer = new byte[2048]; - - System.out.println("Syslog Server läuft auf Port " + SYSLOG_PORT); + System.out.println("[INFO] Syslog-Dienst aktiv auf Port " + SYSLOG_PORT); while (true) { DatagramPacket packet = new DatagramPacket(buffer, buffer.length); socket.receive(packet); int length = packet.getLength(); - - // Länge prüfen if (length > MAX_MESSAGE_LENGTH) { - System.out.println("Nachricht zu lang von " + packet.getAddress()); + System.err.println("[WARN] Nachricht von " + packet.getAddress() + " zu lang. Ignoriert."); continue; } - String message = new String(packet.getData(), 0, length, StandardCharsets.UTF_8); - - // BOM-zeichen ersetzten - message = message.replace("", "Nachricht: "); + String raw = new String(packet.getData(), 0, length, StandardCharsets.UTF_8); + String clean = raw.replace("\uFEFF", "").replace("", ""); - // Zur Sicherheit AUCH noch das Unicode-Zeichen des BOM-Zeichens - message = message.replace("\uFEFF", "Nachricht: "); + // Trennung von Metadaten und Inhalt + int splitIndex = clean.lastIndexOf("]") + 1; + String metadata = "Unbekannt"; + String messageContent = clean; - // Ausgabe mit Client-IP - System.out.println( - "[SYSLOG] Von " + - packet.getAddress().getHostAddress() + - ":" + - packet.getPort() + - " -> " + - message - ); + if (splitIndex > 0 && splitIndex < clean.length()) { + metadata = clean.substring(0, splitIndex).trim(); + messageContent = clean.substring(splitIndex).trim(); + } + + String separator = "=================================================="; + System.out.println("\n" + separator); + System.out.println("NEUE SYSLOG-NACHRICHT"); + System.out.println("Quelle: " + packet.getAddress().getHostAddress() + ":" + packet.getPort()); + System.out.println("Metadaten: " + metadata); + System.out.println("Inhalt: " + messageContent); + System.out.println(separator); } } catch (IOException e) { - e.printStackTrace(); + System.err.println("[ERROR] Syslog-Server Fehler: " + e.getMessage()); } } private static void runDiscoveryServer() { try (DatagramSocket socket = new DatagramSocket(DISCOVERY_PORT)) { byte[] buffer = new byte[256]; - - System.out.println("Discovery Service läuft auf Port " + DISCOVERY_PORT); + System.out.println("[INFO] Discovery-Service aktiv auf Port " + DISCOVERY_PORT); while (true) { DatagramPacket request = new DatagramPacket(buffer, buffer.length); socket.receive(request); - InetAddress clientAddress = request.getAddress(); - int clientPort = request.getPort(); - - System.out.println( - "[DISCOVERY] Anfrage von " + - clientAddress.getHostAddress() - ); - - // Antwort leer(laut Aufgabe) - byte[] responseData = new byte[0]; - DatagramPacket response = new DatagramPacket( - responseData, - responseData.length, - clientAddress, - clientPort + new byte[0], 0, request.getAddress(), request.getPort() ); - socket.send(response); - - System.out.println( - "[DISCOVERY] Antwort gesendet an " + - clientAddress.getHostAddress() - ); + System.out.println("[DISCOVERY] Server-IP an Client mit der IP [" + request.getAddress().getHostAddress() + "] gemeldet."); } } catch (IOException e) { - e.printStackTrace(); + System.err.println("[ERROR] Discovery-Fehler: " + e.getMessage()); } } } \ No newline at end of file