Netzwerkprotokolle: TCP, UDP, IP, DNS, HTTP/HTTPS & OSI/TCP-IP-Modelle
Dieser Beitrag ist eine umfassende Einführung in die Netzwerkprotokolle – inklusive TCP, UDP, IP, DNS, HTTP/HTTPS, OSI-Modell und TCP/IP-Stack mit praktischen Beispielen.
In a Nutshell
Netzwerkprotokolle regeln die Kommunikation zwischen Computern. TCP/IP ist das grundlegende Protokoll-Stack, OSI beschreibt 7 Schichten, HTTP/HTTPS ermöglichen Web-Kommunikation und DNS löst Namen in IPs auf.
Kompakte Fachbeschreibung
Netzwerkprotokolle sind standardisierte Regeln und Konventionen für die Datenkommunikation zwischen Computern in einem Netzwerk.
Wichtige Protokolle:
TCP (Transmission Control Protocol)
- Typ: Verbindungsorientiert, zuverlässig
- Features: 3-Wege-Handshake, Flusskontrolle, Fehlerkorrektur
- Anwendung: Web, E-Mail, Dateitransfer
- Port: 80 (HTTP), 443 (HTTPS), 25 (SMTP)
UDP (User Datagram Protocol)
- Typ: Verbindungslos, unzuverlässig
- Features: Einfach, schnell, keine Garantien
- Anwendung: Streaming, Gaming, DNS
- Port: 53 (DNS), 123 (NTP), 67 (DHCP)
IP (Internet Protocol)
- Typ: Paketvermittlung, Routing
- Versionen: IPv4 (32 Bit), IPv6 (128 Bit)
- Features: Adressierung, Fragmentierung
- Anwendung: Grundlage für Internet
DNS (Domain Name System)
- Typ: Namensauflösung
- Funktion: Domain → IP-Adresse
- Record-Typen: A, AAAA, MX, NS, CNAME
- Port: 53 (UDP/TCP)
HTTP/HTTPS (Hypertext Transfer Protocol)
- Typ: Anwendungsprotokoll für Web
- Methoden: GET, POST, PUT, DELETE
- Status: 200 OK, 404 Not Found, 500 Server Error
- Port: 80 (HTTP), 443 (HTTPS)
Prüfungsrelevante Stichpunkte
- Netzwerkprotokolle: Regeln für computergestützte Kommunikation
- TCP: Verbindungsorientiert, zuverlässig, 3-Wege-Handshake
- UDP: Verbindungslos, schnell, unzuverlässig, Streaming
- IP: Paketvermittlung, Routing, IPv4/IPv6
- DNS: Namensauflösung, Domain → IP-Adresse
- HTTP/HTTPS: Web-Kommunikation, Request/Response
- OSI-Modell: 7-Schichten-Modell für Netzwerkkommunikation
- TCP/IP-Stack: 4-Schichten-Modell, praktische Implementierung
- IHK-relevant: Grundlage für Netzwerkadministration und -entwicklung
Kernkomponenten
- OSI-Modell: Theoretisches 7-Schichten-Modell
- TCP/IP-Stack: Praktisches 4-Schichten-Modell
- Transportprotokolle: TCP, UDP für Datentransport
- Netzwerkprotokolle: IP für Routing und Adressierung
- Anwendungsprotokolle: HTTP, DNS, SMTP für Dienste
- Port-Nummern: Identifikation von Diensten
- Socket-Programmierung: Netzwerk-Kommunikation
- Netzwerk-Sicherheit: Firewalls, VPN, TLS
Praxisbeispiele
1. TCP Socket-Programmierung mit Java
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class TCPServerDemo {
private static final int PORT = 8080;
private static final int MAX_CLIENTS = 10;
public static void main(String[] args) {
System.out.println("=== TCP Server Demo ===");
// Thread Pool für Client-Verbindungen
ExecutorService threadPool = Executors.newFixedThreadPool(MAX_CLIENTS);
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("TCP Server gestartet auf Port " + PORT);
while (true) {
// Auf Client-Verbindungen warten
Socket clientSocket = serverSocket.accept();
System.out.println("Neuer Client verbunden: " + clientSocket.getInetAddress());
// Client in separatem Thread behandeln
threadPool.execute(new ClientHandler(clientSocket));
}
} catch (IOException e) {
System.err.println("Server-Fehler: " + e.getMessage());
} finally {
threadPool.shutdown();
}
}
// Client-Handler
static class ClientHandler implements Runnable {
private final Socket clientSocket;
public ClientHandler(Socket socket) {
this.clientSocket = socket;
}
@Override
public void run() {
try (
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true)
) {
String clientAddress = clientSocket.getInetAddress().toString();
System.out.println("Handler für " + clientAddress + " gestartet");
// Begrüßung senden
out.println("Willkommen beim TCP Server!");
out.println("Type 'exit' to disconnect");
// Nachrichten vom Client empfangen und beantworten
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Nachricht von " + clientAddress + ": " + inputLine);
if ("exit".equalsIgnoreCase(inputLine.trim())) {
out.println("Goodbye!");
break;
}
// Echo mit Timestamp
String response = "Echo: " + inputLine + " [" +
java.time.LocalDateTime.now() + "]";
out.println(response);
}
} catch (IOException e) {
System.err.println("Fehler bei Client-Handler: " + e.getMessage());
} finally {
try {
clientSocket.close();
System.out.println("Client-Verbindung geschlossen");
} catch (IOException e) {
System.err.println("Fehler beim Schließen der Verbindung: " + e.getMessage());
}
}
}
}
// TCP Client
static class TCPClient {
private final String hostname;
private final int port;
public TCPClient(String hostname, int port) {
this.hostname = hostname;
this.port = port;
}
public void start() {
try (
Socket socket = new Socket(hostname, port);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true);
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in))
) {
System.out.println("Mit Server verbunden");
// Server-Antwort empfangen
String serverResponse = in.readLine();
System.out.println("Server: " + serverResponse);
// Interaktive Kommunikation
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
serverResponse = in.readLine();
System.out.println("Server: " + serverResponse);
if ("exit".equalsIgnoreCase(userInput.trim())) {
break;
}
}
} catch (UnknownHostException e) {
System.err.println("Unbekannter Host: " + hostname);
} catch (IOException e) {
System.err.println("I/O Fehler: " + e.getMessage());
}
}
}
// TCP Performance Test
static class TCPPerformanceTest {
public static void testTCPLatency(String hostname, int port, int iterations) {
try (Socket socket = new Socket(hostname, port);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
System.out.println("=== TCP Latency Test ===");
long totalTime = 0;
for (int i = 0; i < iterations; i++) {
long startTime = System.nanoTime();
out.println("ping");
String response = in.readLine();
long endTime = System.nanoTime();
long latency = (endTime - startTime) / 1_000_000; // ms
totalTime += latency;
if (i % 10 == 0) {
System.out.printf("Ping %d: %dms%n", i + 1, latency);
}
}
double avgLatency = (double) totalTime / iterations;
System.out.printf("Durchschnittliche Latenz: %.2fms%n", avgLatency);
} catch (IOException e) {
System.err.println("Fehler bei Latenz-Test: " + e.getMessage());
}
}
public static void testTCPThroughput(String hostname, int port, int dataSize) {
try (Socket socket = new Socket(hostname, port);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
System.out.println("=== TCP Throughput Test ===");
// Testdaten erstellen
StringBuilder testData = new StringBuilder();
for (int i = 0; i < dataSize; i++) {
testData.append("A");
}
long startTime = System.nanoTime();
out.println("throughput:" + testData.toString());
String response = in.readLine();
long endTime = System.nanoTime();
long duration = (endTime - startTime) / 1_000_000; // ms
double throughput = (double) dataSize / (duration / 1000.0) / 1024.0; // KB/s
System.out.printf("Durchsatz: %.2f KB/s (%d Bytes in %dms)%n",
throughput, dataSize, duration);
} catch (IOException e) {
System.err.println("Fehler bei Throughput-Test: " + e.getMessage());
}
}
}
// Main für Client-Tests
public static void main(String[] args) {
// Server starten
if (args.length == 0) {
TCPServerDemo.main(args);
} else {
// Client-Tests
TCPClient client = new TCPClient("localhost", PORT);
// Interaktiver Client
new Thread(() -> client.start()).start();
// Performance Tests
try {
Thread.sleep(2000); // Warten bis Server bereit
TCPPerformanceTest.testTCPLatency("localhost", PORT, 100);
TCPPerformanceTest.testTCPThroughput("localhost", PORT, 10240);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
2. UDP Socket-Programmierung mit Python
import socket
import threading
import time
import json
from datetime import datetime
# UDP Server
class UDPServer:
def __init__(self, host='localhost', port=9999):
self.host = host
self.port = port
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.clients = set()
self.running = False
def start(self):
"""Start des UDP Servers"""
self.server_socket.bind((self.host, self.port))
self.running = True
print(f"UDP Server läuft auf {self.host}:{self.port}")
while self.running:
try:
# Daten empfangen
data, client_address = self.server_socket.recvfrom(2048)
# Client zur Liste hinzufügen
self.clients.add(client_address)
print(f"Nachricht von {client_address}: {data.decode()}")
# Nachricht an alle Clients senden (Broadcast)
self.broadcast(data, client_address)
except Exception as e:
print(f"Fehler beim Empfangen: {e}")
def broadcast(self, message, sender_address):
"""Nachricht an alle Clients senden"""
timestamp = datetime.now().strftime("%H:%M:%S")
broadcast_message = f"[{timestamp}] {sender_address[0]}: {message.decode()}"
for client in self.clients:
if client != sender_address:
try:
self.server_socket.sendto(broadcast_message.encode(), client)
except Exception as e:
print(f"Fehler beim Senden an {client}: {e}")
def stop(self):
"""Server stoppen"""
self.running = False
self.server_socket.close()
print("UDP Server gestoppt")
# UDP Client
class UDPClient:
def __init__(self, host='localhost', port=9999):
self.host = host
self.port = port
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.running = False
def start(self, username):
"""Start des UDP Clients"""
self.running = True
print(f"UDP Client verbunden mit {self.host}:{self.port}")
# Empfangs-Thread starten
receive_thread = threading.Thread(target=self.receive_messages)
receive_thread.daemon = True
receive_thread.start()
try:
while self.running:
# Nachricht eingeben
message = input(f"{username}: ")
if message.lower() == 'exit':
break
# Nachricht senden
full_message = f"{username}: {message}"
self.client_socket.sendto(full_message.encode(), (self.host, self.port))
except KeyboardInterrupt:
print("\nClient beendet")
finally:
self.stop()
def receive_messages(self):
"""Nachrichten vom Server empfangen"""
while self.running:
try:
data, server = self.client_socket.recvfrom(2048)
print(f"\r{data.decode()}")
print("Nachricht: ", end="", flush=True)
except Exception as e:
if self.running:
print(f"Fehler beim Empfangen: {e}")
break
def stop(self):
"""Client stoppen"""
self.running = False
self.client_socket.close()
print("UDP Client gestoppt")
# UDP Performance Test
class UDPPerformanceTest:
def __init__(self, host='localhost', port=9999):
self.host = host
self.port = port
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def test_latency(self, iterations=100):
"""UDP Latenz Test"""
print(f"=== UDP Latency Test ===")
latencies = []
for i in range(iterations):
start_time = time.time()
# Ping-Nachricht senden
self.socket.sendto(b"ping", (self.host, self.port))
# Antwort empfangen
try:
data, _ = self.socket.recvfrom(1024)
end_time = time.time()
latency = (end_time - start_time) * 1000 # ms
latencies.append(latency)
if i % 10 == 0:
print(f"Ping {i+1}: {latency:.2f}ms")
except socket.timeout:
print(f"Timeout bei Ping {i+1}")
if latencies:
avg_latency = sum(latencies) / len(latencies)
min_latency = min(latencies)
max_latency = max(latencies)
print(f"\nLatenz-Statistik:")
print(f" Durchschnitt: {avg_latency:.2f}ms")
print(f" Minimum: {min_latency:.2f}ms")
print(f" Maximum: {max_latency:.2f}ms")
def test_throughput(self, data_size=1024, duration=5):
"""UDP Throughput Test"""
print(f"\n=== UDP Throughput Test ===")
# Testdaten erstellen
test_data = b'A' * data_size
start_time = time.time()
packets_sent = 0
while time.time() - start_time < duration:
try:
self.socket.sendto(test_data, (self.host, self.port))
packets_sent += 0
# Kurze Pause um Server nicht zu überlasten
time.sleep(0.001)
except Exception as e:
print(f"Fehler beim Senden: {e}")
break
end_time = time.time()
total_time = end_time - start_time
throughput = (packets_sent * data_size) / total_time / 1024 # KB/s
packets_per_second = packets_sent / total_time
print(f"Throughput-Statistik:")
print(f" Pakete gesendet: {packets_sent}")
print(f " Gesamtdauer: {total_time:.2f}s")
print(f" Pakete/Sekunde: {packets_per_second:.2f}")
print(f" Durchsatz: {throughput:.2f} KB/s")
def test_packet_loss(self, packets=1000):
"""UDP Packet Loss Test"""
print(f"\n=== UDP Packet Loss Test ===")
packets_lost = 0
for i in range(packets):
try:
# Sequenzielle Nummer senden
packet = f"packet_{i}".encode()
self.socket.sendto(packet, (self.host, self.port))
# Kurze Pause
time.sleep(0.001)
except Exception as e:
packets_lost += 1
loss_rate = (packets_lost / packets) * 100
print(f"Packet Loss Statistik:")
print(f" Pakete gesendet: {packets}")
print(f" Pakete verloren: {packets_lost}")
print(f" Verlustrate: {loss_rate:.2f}%")
def close(self):
"""Socket schließen"""
self.socket.close()
# UDP Multicast Demo
class UDPMulticastDemo:
def __init__(self, multicast_group='224.0.0.1', port=5000):
self.multicast_group = multicast_group
self.port = port
def create_multicast_sender(self):
"""Multicast Sender erstellen"""
sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# TTL setzen (wie viele Hops das Paket machen darf)
ttl = struct.pack('b', 1)
sender.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
return sender
def create_multicast_receiver(self):
"""Multicast Receiver erstellen"""
receiver = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Socket an Multicast-Adresse binden
receiver.bind(('', self.port))
# Der Multicast-Gruppe beitreten
group = socket.inet_aton(self.multicast_group)
receiver.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, group + socket.inet_aton('0.0.0.0'))
return receiver
def send_multicast(self, message):
"""Multicast-Nachricht senden"""
sender = self.create_multicast_sender()
try:
sender.sendto(message.encode(), (self.multicast_group, self.port))
print(f"Multicast gesendet: {message}")
finally:
sender.close()
def receive_multicast(self):
"""Multicast-Nachrichten empfangen"""
receiver = self.create_multicast_receiver()
try:
print(f"Multicast Receiver lauscht auf {self.multicast_group}:{self.port}")
while True:
try:
data, address = receiver.recvfrom(1024)
print(f"Multicast von {address}: {data.decode()}")
except KeyboardInterrupt:
break
finally:
# Gruppe verlassen
group = socket.inet_aton(self.multicast_group)
receiver.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, group + socket.inet_aton('0.0.0.0'))
receiver.close()
# Main für UDP-Demos
def main():
import sys
if len(sys.argv) > 1:
mode = sys.argv[1]
if mode == "server":
# UDP Server starten
server = UDPServer()
try:
server.start()
except KeyboardInterrupt:
server.stop()
elif mode == "client":
# UDP Client starten
username = input("Ihr Name: ")
client = UDPClient()
client.start(username)
elif mode == "performance":
# Performance Tests
test = UDPPerformanceTest()
test.test_latency(100)
test.test_throughput(1024, 5)
test.test_packet_loss(1000)
test.close()
elif mode == "multicast_send":
# Multicast Sender
multicast = UDPMulticastDemo()
while True:
message = input("Multicast-Nachricht (oder 'exit'): ")
if message.lower() == 'exit':
break
multicast.send_multicast(message)
elif mode == "multicast_receive":
# Multicast Receiver
multicast = UDPMulticastDemo()
multicast.receive_multicast()
else:
print("Verwendung: python udp_demo.py [server|client|performance|multicast_send|multicast_receive]")
else:
print("Verwendung: python udp_demo.py [server|client|performance|multicast_send|multicast_receive]")
if __name__ == "__main__":
main()
3. DNS-Abfragen mit verschiedenen Programmiersprachen
import java.net.*;
import java.util.*;
public class DNSLookupDemo {
// Einfache DNS-Abfrage
public static String dnsLookup(String hostname) {
try {
InetAddress address = InetAddress.getByName(hostname);
return address.getHostAddress();
} catch (UnknownHostException e) {
return "Unknown host: " + hostname;
}
}
// Reverse DNS-Abfrage (IP → Hostname)
public static String reverseDNSLookup(String ipAddress) {
try {
InetAddress address = InetAddress.getByName(ipAddress);
return address.getHostName();
} catch (UnknownHostException e) {
return "Unknown IP: " + ipAddress;
}
}
// Alle IP-Adressen für einen Hostnamen
public static List<String> getAllIPAddresses(String hostname) {
List<String> addresses = new ArrayList<>();
try {
InetAddress[] allAddresses = InetAddress.getAllByName(hostname);
for (InetAddress addr : allAddresses) {
addresses.add(addr.getHostAddress());
}
} catch (UnknownHostException e) {
addresses.add("Unknown host: " + hostname);
}
return addresses;
}
// DNS-Record-Typen abfragen (vereinfacht)
public static void dnsLookupWithTypes(String hostname) {
System.out.println("=== DNS Lookup für " + hostname + " ===");
// A-Record (IPv4)
String ipv4 = dnsLookup(hostname);
System.out.println("A-Record (IPv4): " + ipv4);
// AAAA-Record (IPv6)
try {
InetAddress ipv6Address = InetAddress.getByName(hostname);
if (ipv6Address instanceof Inet6Address) {
System.out.println("AAAA-Record (IPv6): " + ipv6Address.getHostAddress());
}
} catch (UnknownHostException e) {
System.out.println("AAAA-Record (IPv6): Nicht gefunden");
}
// Reverse Lookup
if (!ipv4.equals("Unknown host: " + hostname)) {
String reverse = reverseDNSLookup(ipv4);
System.out.println("PTR-Record (Reverse): " + reverse);
}
// MX-Records (Mail Exchange)
dnsLookupMX(hostname);
// NS-Records (Name Server)
dnsLookupNS(hostname);
}
// MX-Records abfragen
public static void dnsLookupMX(String hostname) {
try {
// In der Praxis würde man DNS-Bibliotheken wie dnsjava verwenden
// Hier zeigen wir das Konzept
System.out.println("MX-Records: Verwendet DNS-Bibliotheken für vollständige Abfrage");
// Beispiel mit einfacher Logik
if (hostname.endsWith(".com")) {
System.out.println(" MX: mail." + hostname + " (Beispiel)");
}
} catch (Exception e) {
System.out.println("MX-Records: Fehler bei Abfrage - " + e.getMessage());
}
}
// NS-Records abfragen
public static void dnsLookupNS(String hostname) {
try {
System.out.println("NS-Records: Verwendet DNS-Bibliotheken für vollständige Abfrage");
// Beispiel mit einfacher Logik
String[] commonNS = {"ns1." + hostname, "ns2." + hostname};
for (String ns : commonNS) {
System.out.println(" NS: " + ns + " (Beispiel)");
}
} catch (Exception e) {
System.out.println("NS-Records: Fehler bei Abfrage - " + e.getMessage());
}
}
// DNS-Performance-Test
public static void dnsPerformanceTest(String hostname, int iterations) {
System.out.println("=== DNS Performance Test ===");
long totalTime = 0;
int successfulLookups = 0;
for (int i = 0; i < iterations; i++) {
long startTime = System.nanoTime();
String result = dnsLookup(hostname);
long endTime = System.nanoTime();
long duration = (endTime - startTime) / 1_000_000; // ms
if (!result.startsWith("Unknown host")) {
totalTime += duration;
successfulLookups++;
}
if (i % 10 == 0) {
System.out.printf("Lookup %d: %dms%n", i + 1, duration);
}
}
if (successfulLookups > 0) {
double avgTime = (double) totalTime / successfulLookups;
System.out.printf("Durchschnittliche DNS-Lookup Zeit: %.2fms%n", avgTime);
System.out.printf("Erfolgreiche Lookups: %d/%d%n", successfulLookups, iterations);
}
}
// DNS-Caching Demo
public static void dnsCachingDemo(String hostname) {
System.out.println("=== DNS Caching Demo ===");
// Erster Lookup (Cache-Miss)
long start = System.nanoTime();
String result1 = dnsLookup(hostname);
long firstLookup = (System.nanoTime() - start) / 1_000_000;
// Zweiter Lookup (Cache-Hit)
start = System.nanoTime();
String result2 = dnsLookup(hostname);
long secondLookup = (System.nanoTime() - start) / 1_000_000;
System.out.println("Erster Lookup: " + firstLookup + "ms");
System.out.println("Zweiter Lookup: " + secondLookup + "ms");
if (secondLookup < firstLookup) {
System.out.println("DNS-Caching aktiv (zweiter Lookup schneller)");
} else {
System.out.println("Kein DNS-Caching erkannt");
}
// Ergebnisse vergleichen
System.out.println("Ergebnis 1: " + result1);
System.out.println("Ergebnis 2: " + result2);
System.out.println("Ergebnisse gleich: " + result1.equals(result2));
}
// IPv6 Support Test
public static void ipv6SupportTest(String hostname) {
System.out.println("=== IPv6 Support Test ===");
try {
// IPv6-Adresse auflösen
InetAddress[] addresses = InetAddress.getAllByName(hostname);
boolean hasIPv4 = false;
boolean hasIPv6 = false;
for (InetAddress addr : addresses) {
if (addr instanceof Inet4Address) {
hasIPv4 = true;
System.out.println("IPv4: " + addr.getHostAddress());
} else if (addr instanceof Inet6Address) {
hasIPv6 = true;
System.out.println("IPv6: " + addr.getHostAddress());
}
}
System.out.println("IPv4 Support: " + (hasIPv4 ? "Ja" : "Nein"));
System.out.println("IPv6 Support: " + (hasIPv6 ? "Ja" : "Nein"));
} catch (UnknownHostException e) {
System.out.println("IPv6 Support Test fehlgeschlagen: " + e.getMessage());
}
}
public static void main(String[] args) {
String hostname = "google.com";
if (args.length > 0) {
hostname = args[0];
}
// Verschiedene DNS-Abfragen
dnsLookupWithTypes(hostname);
// Performance-Test
dnsPerformanceTest(hostname, 50);
// Caching-Demo
dnsCachingDemo(hostname);
// IPv6 Support Test
ipv6SupportTest(hostname);
}
}
4. HTTP/HTTPS Client mit verschiedenen Features
import requests
import json
import time
import ssl
import urllib3
from urllib3.util.retry import Retry
from datetime import datetime
# HTTP Client mit erweiterten Features
class HTTPClient:
def __init__(self):
self.session = requests.Session()
self.setup_session()
def setup_session(self):
"""Session konfigurieren"""
# Retry-Strategie
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["HEAD", "GET", "OPTIONS"]
)
adapter = urllib3.HTTPAdapter(max_retries=retry_strategy)
self.session.mount("https://", adapter)
self.session.mount("http://", adapter)
# Headers
self.session.headers.update({
'User-Agent': 'HTTPClient-Demo/1.0',
'Accept': 'application/json',
'Accept-Language': 'de-DE,de;q=0.9,en;q=0.8',
'Cache-Control': 'no-cache'
})
# Timeout
self.session.timeout = 30
print("HTTP Client konfiguriert")
def get_request(self, url, params=None):
"""GET-Request mit Fehlerbehandlung"""
try:
print(f"GET Request: {url}")
start_time = time.time()
response = self.session.get(url, params=params)
end_time = time.time()
self.print_response_info(response, end_time - start_time)
return response
except requests.exceptions.RequestException as e:
print(f"GET Request fehlgeschlagen: {e}")
return None
def post_request(self, url, data=None, json_data=None):
"""POST-Request mit Daten"""
try:
print(f"POST Request: {url}")
if json_data:
print(f"JSON-Daten: {json.dumps(json_data, indent=2)}")
start_time = time.time()
if json_data:
response = self.session.post(url, json=json_data)
else:
response = self.session.post(url, data=data)
end_time = time.time()
self.print_response_info(response, end_time - start_time)
return response
except requests.exceptions.RequestException as e:
print(f"POST Request fehlgeschlagen: {e}")
return None
def print_response_info(self, response, duration):
"""Response-Informationen ausgeben"""
print(f"Status Code: {response.status_code}")
print(f"Response Time: {duration:.2f}s")
print(f"Content-Type: {response.headers.get('Content-Type', 'N/A')}")
print(f"Content-Length: {response.headers.get('Content-Length', 'N/A')}")
# Headers ausgeben
if response.headers:
print("Response Headers:")
for key, value in response.headers.items():
print(f" {key}: {value}")
def test_http_methods(self, url):
"""Verschiedene HTTP-Methoden testen"""
print(f"=== HTTP Methods Test für {url} ===")
# GET
print("\n--- GET ---")
response = self.get_request(url)
# HEAD
print("\n--- HEAD ---")
try:
response = self.session.head(url)
print(f"HEAD Status: {response.status_code}")
print(f"HEAD Headers: {dict(response.headers)}")
except Exception as e:
print(f"HEAD Request fehlgeschlagen: {e}")
# OPTIONS
print("\n--- OPTIONS ---")
try:
response = self.session.options(url)
print(f"OPTIONS Status: {response.status_code}")
allowed_methods = response.headers.get('Allow', 'N/A')
print(f"Erlaubte Methoden: {allowed_methods}")
except Exception as e:
print(f"OPTIONS Request fehlgeschlagen: {e}")
def test_https_features(self, url):
"""HTTPS-Features testen"""
print(f"=== HTTPS Features Test für {url} ===")
try:
# SSL-Zertifikat-Informationen
response = self.session.get(url)
# SSL-Informationen ausgeben
cert_info = response.raw._connection.peer.cert
if cert_info:
print("SSL-Zertifikat-Informationen:")
for cert in cert_info:
print(f" Subject: {cert.subject}")
print(f" Issuer: {cert.issuer}")
print(f" Valid from: {cert.not_valid_before}")
print(f" Valid until: {cert.not_valid_after}")
print(f" Serial: {cert.serial_number}")
# TLS-Version
tls_version = response.raw._connection.tls_version
print(f"TLS-Version: {tls_version}")
# Cipher Suite
cipher_suite = response.raw._connection.cipher
print(f"Cipher Suite: {cipher_suite}")
except Exception as e:
print(f"HTTPS Features Test fehlgeschlagen: {e}")
def test_authentication(self, url, username, password):
"""HTTP-Authentifizierung testen"""
print(f"=== Authentication Test für {url} ===")
# Basic Authentication
try:
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth(username, password)
response = self.session.get(url, auth=auth)
print(f"Basic Auth Status: {response.status_code}")
if response.status_code == 200:
print("Basic Authentication erfolgreich")
else:
print("Basic Authentication fehlgeschlagen")
except Exception as e:
print(f"Authentication Test fehlgeschlagen: {e}")
def test_cookies(self, url):
"""Cookie-Handling testen"""
print(f"=== Cookie Test für {url} ===")
try:
# Erste Request ohne Cookies
response1 = self.session.get(url)
print(f"Erster Request Status: {response1.status_code}")
print(f"Cookies nach erstem Request: {len(self.session.cookies)}")
# Zweiter Request mit Cookies
response2 = self.session.get(url)
print(f"Zweiter Request Status: {response2.status_code}")
print(f"Cookies nach zweitem Request: {len(self.session.cookies)}")
# Cookie-Informationen
if self.session.cookies:
print("Cookie-Details:")
for cookie in self.session.cookies:
print(f" {cookie.name}: {cookie.value}")
print(f" Domain: {cookie.domain}")
print(f" Path: {cookie.path}")
print(f" Secure: {cookie.secure}")
print(f" HttpOnly: {cookie.has_attr('HttpOnly')}")
except Exception as e:
print(f"Cookie Test fehlgeschlagen: {e}")
def test_redirects(self, url):
"""Redirect-Handling testen"""
print(f"=== Redirect Test für {url} ===")
try:
# Redirects nicht folgen
response = self.session.get(url, allow_redirects=False)
print(f"Status ohne Redirects: {response.status_code}")
if 300 <= response.status_code < 400:
location = response.headers.get('Location', 'N/A')
print(f"Redirect zu: {location}")
# Redirects folgen
response = self.session.get(url, allow_redirects=True)
print(f"Status mit Redirects: {response.status_code}")
print(f"Final URL: {response.url}")
# Redirect-Verlauf
if hasattr(response.history, '__iter__'):
print("Redirect-Verlauf:")
for i, resp in enumerate(response.history):
print(f" {i+1}. {resp.status_code} -> {resp.url}")
except Exception as e:
print(f"Redirect Test fehlgeschlagen: {e}")
def test_download(self, url, save_path=None):
"""Datei-Download testen"""
print(f"=== Download Test für {url} ===")
try:
response = self.session.get(url, stream=True)
content_length = int(response.headers.get('content-length', 0))
print(f"Dateigröße: {content_length} bytes")
if save_path:
with open(save_path, 'wb') as f:
downloaded = 0
chunk_size = 8192
for chunk in response.iter_content(chunk_size=chunk_size):
f.write(chunk)
downloaded += chunk_size
# Progress anzeigen
progress = (downloaded / content_length) * 100 if content_length > 0 else 0
print(f"\rDownload: {progress:.1f}%", end="", flush=True)
print(f"\nDatei gespeichert: {save_path}")
except Exception as e:
print(f"Download fehlgeschlagen: {e}")
def performance_test(self, url, iterations=10):
"""Performance-Test"""
print(f"=== Performance Test für {url} ===")
times = []
for i in range(iterations):
try:
start_time = time.time()
response = self.session.get(url)
end_time = time.time()
duration = end_time - start_time
times.append(duration)
if i % 5 == 0:
print(f"Request {i+1}: {duration:.3f}s")
except Exception as e:
print(f"Request {i+1} fehlgeschlagen: {e}")
if times:
avg_time = sum(times) / len(times)
min_time = min(times)
max_time = max(times)
print(f"\nPerformance-Statistik:")
print(f" Requests: {len(times)}")
print(f" Durchschnitt: {avg_time:.3f}s")
print(f" Minimum: {min_time:.3f}s")
print(f" Maximum: {max_time:.3f}s")
print(f" Requests/Sekunde: {1/avg_time:.2f}")
# API-Client für REST-APIs
class APIClient(HTTPClient):
def __init__(self, base_url):
super().__init__()
self.base_url = base_url.rstrip('/')
# API-spezifische Headers
self.session.headers.update({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
def get_resource(self, resource, params=None):
"""GET Resource"""
url = f"{self.base_url}/{resource.lstrip('/')}"
return self.get_request(url, params)
def create_resource(self, resource, data):
"""POST Resource"""
url = f"{self.base_url}/{resource.lstrip('/')}"
return self.post_request(url, json_data=data)
def update_resource(self, resource, data):
"""PUT Resource"""
url = f"{self.base_url}/{resource.lstrip('/')}"
try:
response = self.session.put(url, json=data)
self.print_response_info(response, 0)
return response
except Exception as e:
print(f"PUT Request fehlgeschlagen: {e}")
return None
def delete_resource(self, resource):
"""DELETE Resource"""
url = f"{self.base_url}/{resource.lstrip('/')}"
try:
response = self.session.delete(url)
self.print_response_info(response, 0)
return response
except Exception as e:
print(f"DELETE Request fehlgeschlagen: {e}")
return None
# Main für HTTP-Demos
def main():
import sys
# HTTP Client Demo
client = HTTPClient()
# HTTP-Methoden Test
client.test_http_methods("https://httpbin.org")
# HTTPS Features Test
client.test_https_features("https://google.com")
# Redirect Test
client.test_redirects("http://httpbin.org/redirect/1")
# Cookie Test
client.test_cookies("https://httpbin.org/cookies/set/test/value")
# Performance Test
client.performance_test("https://httpbin.org/get", 20)
# API Client Demo
api_client = APIClient("https://jsonplaceholder.typicode.com")
# GET Users
users_response = api_client.get_resource("/users")
if users_response:
print(f"Users: {users_response.json()}")
# Create Post
new_post = {
"title": "Test Post",
"body": "Test Body",
"userId": 1
}
create_response = api_client.create_resource("/posts", new_post)
# Download Test
client.test_download("https://httpbin.org/bytes/1024", "test_download.bin")
if __name__ == "__main__":
main()
OSI-Modell vs TCP/IP-Stack
OSI-Modell (7 Schichten)
| Schicht | Name | Funktion | Beispiele |
|---|---|---|---|
| 7 | Application | Anwendungsprotokolle | HTTP, FTP, SMTP |
| 6 | Presentation | Datenumwandlung | SSL/TLS, JPEG |
| 5 | Session | Sitzungsverwaltung | NetBIOS, RPC |
| 4 | Transport | End-to-End-Kommunikation | TCP, UDP |
| 3 | Network | Routing und Adressierung | IP, ICMP |
| 2 | Data Link | Frame-Übertragung | Ethernet, WiFi |
| 1 | Physical | Bit-Übertragung | Kabel, Funk |
TCP/IP-Stack (4 Schichten)
| Schicht | Name | OSI-Entsprechung | Protokolle |
|---|---|---|---|
| 4 | Application | 5-7 | HTTP, FTP, DNS |
| 3 | Transport | 4 | TCP, UDP |
| 2 | Internet | 3 | IP, ICMP |
| 1 | Network Access | 1-2 | Ethernet, WiFi |
Wichtige Port-Nummern
Well-Known Ports (0-1023)
| Port | Protokoll | Dienst |
|---|---|---|
| 20 | FTP | File Transfer (Data) |
| 21 | FTP | File Transfer (Control) |
| 22 | SSH | Secure Shell |
| 23 | Telnet | Remote Terminal |
| 25 | SMTP | |
| 53 | DNS | Domain Name System |
| 80 | HTTP | Web (unverschlüsselt) |
| 110 | POP3 | E-Mail (Post Office) |
| 143 | IMAP | E-Mail (Internet Message) |
| 443 | HTTPS | Web (verschlüsselt) |
| 993 | IMAPS | IMAP over SSL |
| 995 | POP3S | POP3 over SSL |
Registered Ports (1024-49151)
| Port | Protokoll | Dienst |
|---|---|---|
| 3306 | MySQL | Datenbank |
| 5432 | PostgreSQL | Datenbank |
| 8080 | HTTP-Alt | Web (alternativ) |
| 8443 | HTTPS-Alt | Web (alternativ) |
| 27017 | MongoDB | NoSQL-Datenbank |
TCP vs UDP Vergleich
| Eigenschaft | TCP | UDP |
|---|---|---|
| Verbindung | Verbindungsorientiert | Verbindungslos |
| Zuverlässigkeit | Garantiert | Nicht garantiert |
| Reihenfolge | Garantiert | Nicht garantiert |
| Flusskontrolle | Ja | Nein |
| Fehlerkorrektur | Ja | Nein |
| Overhead | Hoch | Niedrig |
| Geschwindigkeit | Langsamer | Schneller |
| Anwendung | Web, E-Mail | Streaming, Gaming |
HTTP-Statuscodes Übersicht
1xx Informational
- 100 Continue: Fortsetzung
- 101 Switching Protocols: Protokoll-Wechsel
2xx Success
- 200 OK: Erfolgreich
- 201 Created: Erstellt
- 204 No Content: Kein Inhalt
3xx Redirection
- 301 Moved Permanently: Permanent verschoben
- 302 Found: Temporär verschoben
- 304 Not Modified: Nicht verändert
4xx Client Error
- 400 Bad Request: Ungültige Anfrage
- 401 Unauthorized: Nicht autorisiert
- 403 Forbidden: Verboten
- 404 Not Found: Nicht gefunden
- 429 Too Many Requests: Zu viele Anfragen
5xx Server Error
- 500 Internal Server Error: Interner Serverfehler
- 502 Bad Gateway: Gateway-Fehler
- 503 Service Unavailable: Dienst nicht verfügbar
DNS-Record-Typen
| Typ | Beschreibung | Beispiel |
|---|---|---|
| A | IPv4-Adresse | example.com → 93.184.216.34 |
| AAAA | IPv6-Adresse | example.com → 2606:2800:220:1 |
| MX | Mail Exchange | example.com → mail.example.com |
| NS | Name Server | example.com → ns1.example.com |
| CNAME | Canonical Name | www.example.com → example.com |
| TXT | Text-Information | example.com → “v=spf1 include:_spf.google.com ~all” |
| PTR | Pointer (Reverse) | 93.184.216.34 → example.com |
Socket-Programmierung Grundlagen
TCP Socket Lifecycle
// Server
1. ServerSocket erstellen
2. Auf Verbindung warten (accept)
3. InputStream/OutputStream erstellen
4. Daten austauschen
5. Verbindung schließen
// Client
1. Socket erstellen
2. Mit Server verbinden
3. InputStream/OutputStream erstellen
4. Daten austauschen
5. Verbindung schließen
UDP Socket Lifecycle
// Server
1. DatagramSocket erstellen
2. Auf Pakete warten (receive)
3. Paket verarbeiten
4. Antwort senden (send)
// Client
1. DatagramSocket erstellen
2. Paket senden (send)
3. Auf Antwort warten (receive)
4. Socket schließen
Vorteile und Nachteile
Vorteile von Netzwerkprotokollen
- Standardisierung: Interoperabilität zwischen Systemen
- Skalierbarkeit: Unterstützung für große Netzwerke
- Zuverlässigkeit: Fehlerbehandlung und Wiederherstellung
- Flexibilität: Verschiedene Protokolle für verschiedene Zwecke
Nachteile
- Komplexität: Viele Schichten und Protokolle
- Overhead: Zusätzliche Daten für Protokoll-Informationen
- Sicherheit: Angriffsflächen für Hacker
- Performance: Netzwerk-Latenzen
Häufige Prüfungsfragen
-
Was ist der Unterschied zwischen TCP und UDP? TCP ist verbindungsorientiert und zuverlässig, UDP ist verbindungslos und schnell aber unzuverlässig.
-
Erklären Sie das OSI-Modell! Das OSI-Modell beschreibt 7 Schichten für Netzwerkkommunikation von Physical bis Application.
-
Was ist DNS und wie funktioniert es? DNS übersetzt Domain-Namen in IP-Adressen und umgekehrt über hierarchische Namenserver.
-
Wann verwendet man HTTP vs HTTPS? HTTP für unverschlüsselte Kommunikation, HTTPS für verschlüsselte Kommunikation mit SSL/TLS.
Wichtigste Quellen
- https://www.ietf.org/rfc/rfc791.html (TCP)
- https://www.ietf.org/rfc/rfc768.html (UDP)
- https://www.ietf.org/rfc/rfc1035.html (DNS)
- https://www.ietf.org/rfc/rfc2616.html (HTTP/1.1)