Verteilte Systeme
Prof. Dr. Alexandra Mikityuk
HTW Berlin
htons) zwischen Rechnern wichtig istIn VL 8 liefen mehrere Prozesse/Threads nebeneinander â aber alle auf derselben Maschine, mit gemeinsamem Speicher.
Threads teilen Speicher â Synchronisation mit Mutex/Semaphor. Kommunikation = gemeinsame Variablen.
Kein gemeinsamer Speicher! Die Prozesse stehen auf verschiedenen Maschinen. Wie reden sie jetzt?
Interprozesskommunikation (IPC) â abhĂ€ngig davon, wo die Prozesse stehen:
| in der Shell)SIGTERM)Fast jede Netz-Kommunikation folgt diesem Muster â wie im Restaurant: ihr bestellt, die KĂŒche liefert.
Ein Socket ist der Endpunkt einer Verbindung â eine âSteckdose", in die euer Programm Daten hineinschreibt und herausliest.
Der Clou: In C fĂŒhlt sich ein Socket an wie eine Datei. Man bekommt einen int (den âFile Descriptor") und nutzt vertraute Operationen â nur heiĂen sie send() / recv() statt write() / read().
Damit eine Nachricht das richtige Programm erreicht, braucht es zwei Angaben:
Welcher Rechner? â wie die Hausanschrift. Z. B. 127.0.0.1 (= âdieser Rechner", localhost).
Welches Programm darauf? â wie die Wohnungsnummer. Z. B. 80 (HTTP), 443 (HTTPS), 8080 (eigene App).
Rechner : Programm
Die IP fĂŒhrt zum richtigen Rechner. Aber dort laufen viele Programme gleichzeitig â der Port sagt, welches gemeint ist.
203.0.113.5:8080 landet genau bei âeurer App" â nicht beim Web- oder Mail-Server.Auf Sockets gibt es zwei Grund-Protokolle â mit komplett unterschiedlicher Philosophie:
Erst Verbindung aufbauen, dann reden. ZuverlÀssig & geordnet: nichts geht verloren, alles kommt in Reihenfolge an.
SOCK_STREAM
Keine Verbindung â einfach abschicken. Schnell, aber ohne Garantie: Pakete können verloren gehen oder die Reihenfolge tauschen.
SOCK_DGRAM
socket(AF_INET, SOCK_STREAM, 0) fĂŒr TCP vs. SOCK_DGRAM fĂŒr UDP. Den Rest schauen wir uns gleich konkret an.
Server und Client durchlaufen feste Schritte. Der Server wartet, der Client verbindet sich.
connect() und der Server-Aufruf accept() finden zusammen â das ist der 3-Wege-Handshake (gleich im Detail). Danach steht eine zuverlĂ€ssige Leitung.
Bevor auch nur ein Byte Nutzdaten flieĂt, begrĂŒĂen sich Client und Server in drei Schritten â wie ein HĂ€ndedruck:
connect() (Client) und accept() (Server). Erst danach gibt es eine zuverlĂ€ssige Leitung â der Preis fĂŒr TCPs Garantie.#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(void) {
int server_fd = socket(AF_INET, SOCK_STREAM, 0); // 1. Socket erstellen
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080); // Port (Byte-Order!)
addr.sin_addr.s_addr = INADDR_ANY; // alle Netzwerk-Interfaces
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)); // 2. Port belegen
listen(server_fd, 5); // 3. Lauschen
int client = accept(server_fd, NULL, NULL); // 4. Auf Client warten
char buf[1024];
int n = recv(client, buf, sizeof(buf)-1, 0); // 5. schreibt Client-Bytes IN buf
buf[n] = '\0';
printf("Empfangen: %s\n", buf);
send(client, buf, n, 0); // 6. Echo: dieselben Bytes aus buf zurĂŒck
close(client); close(server_fd);
return 0;
}
buf ist nur eine leere Box. recv fĂŒllt sie mit dem, was der Client schickt â danach steht âHallo!" in buf. send(client, buf, n, âŠ) schickt genau diese Bytes zurĂŒck. Nichts ist fest verdrahtet: zurĂŒck kommt, was reinkam â âEcho".gcc server.c -o server · ./server â es wartet jetzt auf Port 8080.#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(void) {
int sock = socket(AF_INET, SOCK_STREAM, 0); // 1. Socket
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); // Server-IP
connect(sock, (struct sockaddr*)&addr, sizeof(addr)); // 2. Verbinden
char *msg = "Hallo Server!";
send(sock, msg, strlen(msg), 0); // 3. Senden
char buf[1024];
int n = recv(sock, buf, sizeof(buf)-1, 0); // 4. Antwort empfangen
buf[n] = '\0';
printf("Server antwortete: %s\n", buf);
close(sock);
return 0;
}
So greifen die beiden Programme von vorhin ineinander. Lies von oben nach unten:
htons()? â die Byte-ReihenfolgeVerschiedene CPUs speichern Zahlen in unterschiedlicher Byte-Reihenfolge. Ăber das Netz muss man sich auf eine einigen.
Die Zahl 8080 kann als 1F 90 (Big-Endian) oder 90 1F (Little-Endian) im Speicher liegen â je nach CPU. Schickt man die rohen Bytes, liest der andere evtl. Unsinn.
Im Netz gilt Big-Endian. Funktionen wandeln um:
Lest den Namen einfach Buchstabe fĂŒr Buchstabe:
htons = host to network short (16 Bit, z. B. Port)htonl = host to network long (32 Bit, z. B. IPv4-Adresse)ntohs / ntohl = network to host (zurĂŒck) â short / longWarum beide? Daten reisen in beide Richtungen: beim Senden wandelt ihr eure Zahl in Netz-Reihenfolge (htonâŠ), beim Empfangen wieder zurĂŒck in eure (ntohâŠ).
htons()/htonl() setzen. Vergisst man es, lĂ€uft es auf dem eigenen Rechner vielleicht â aber bricht zwischen zwei verschiedenen Maschinen.
Bevor wir UDP anschauen â das habt ihr bis hier in der Hand:
Endpunkt wie eine Datei. Adresse = IP (Rechner) + Port (Programm).
Server: socketâbindâlistenâaccept. Client: socketâconnect. Dann send/recv.
Zahlen fĂŒrs Netz mit htons/htonl â sonst Chaos zwischen CPUs.
UDP ist verbindungslos: man verschickt einzelne Pakete (Datagramme) â ganz ohne vorher eine Leitung aufzubauen. Darum ist der Code kĂŒrzer.
int s = socket(AF_INET, SOCK_DGRAM, 0);
// addr fĂŒllen (Port 9090, INADDR_ANY)
bind(s, (struct sockaddr*)&addr, sizeof(addr));
struct sockaddr_in cli;
socklen_t len = sizeof(cli);
char buf[1024];
int n = recvfrom(s, buf, 1023, 0,
(struct sockaddr*)&cli, &len);
sendto(s, buf, n, 0,
(struct sockaddr*)&cli, len); // Echo
int s = socket(AF_INET, SOCK_DGRAM, 0);
// addr fĂŒllen (127.0.0.1, Port 9090)
char *msg = "Hallo UDP!";
sendto(s, msg, strlen(msg), 0,
(struct sockaddr*)&addr, sizeof(addr));
char buf[1024];
int n = recvfrom(s, buf, 1023, 0,
NULL, NULL);
listen/accept/connect. Man schickt sofort los.sendto sagt âwohin", recvfrom verrĂ€t âvon wem". Deshalb merkt sich der Server mit &cli den Absender und antwortet genau dorthin.sendto = ein eigenstĂ€ndiges Paket (Datagramm) â unabhĂ€ngig, ohne Reihenfolge-Garantie.Jedes Paket ist nummeriert und wird bestĂ€tigt (ACK). Fehlt eins, wird es neu geschickt â nichts geht verloren, Reihenfolge stimmt.
Pakete werden einfach gesendet â keine BestĂ€tigung, keine Wiederholung. Geht eins verloren, merkt es niemand. DafĂŒr ganz ohne Wartezeit.
| TCP đ | UDP đź | |
|---|---|---|
| Verbindung | ja (Handshake) | nein |
| ZuverlĂ€ssig | â nichts geht verloren | â Pakete können fehlen |
| Reihenfolge | garantiert | nicht garantiert |
| Tempo / Overhead | etwas langsamer | sehr schnell |
| Gut fĂŒr | Web, E-Mail, Dateien, Datenbanken | Live-Video, Online-Spiele, DNS, Voice |
Ein Socket transportiert nur rohe Bytes â er weiĂ nichts ĂŒber deren Bedeutung. Sender und EmpfĂ€nger mĂŒssen sich auf ein Format einigen.
{ "typ": "messung", "sensor": 3, "wert": 21.5 }
Der Server schickt diesen Text durch den Socket; der Client liest die Bytes und parst sie zurĂŒck in Werte.
Was ihr in diesem Kurs schon gesehen habt, lĂ€uft unten ĂŒber Sockets:
Browser â Server ĂŒber einen TCP-Socket auf Port 80/443.
Clients â Broker ĂŒber TCP-Sockets â Publish/Subscribe obendrauf.
Nodes verbinden sich gegenseitig ĂŒber Sockets und tauschen Blöcke aus.
Ihr braucht nicht mal den Client zu schreiben: startet den Echo-Server von vorhin und verbindet euch mit netcat (nc), das auf fast jedem System dabei ist.
$ gcc server.c -o server
$ ./server
# wartet auf Port 8080 ...
Empfangen: Hallo!
$ nc 127.0.0.1 8080
Hallo! â ihr tippt
Hallo! â Echo vom Server
printf â Terminal 1) und schickt dieselben Bytes zurĂŒck (die send(... buf ...) // Echo-Zeile aus dem Server-Code) â Terminal 2 zeigt es an.nc testet ihr jeden TCP-Server, ohne Client-Code. Genau so prĂŒft man auch echte Dienste: âlauscht da was und antwortet es?"Ihr baut ein Online-Spiel: viele Positions-Updates pro Sekunde, ein einzelnes verlorenes Update ist egal. Welches Protokoll passt?
â Klicke auf eine Antwort, um aufzulösen
send/recv).sendto/recvfrom â schnell, aber ohne Garantie.htons/htonl fĂŒr die Byte-Order â sonst bricht es zwischen verschiedenen Rechnern.man socket, man 7 ip, man recvnc 127.0.0.1 8080 (netcat) verbindenss -tlnp / netstat â welche Ports lauschen?NĂ€chstes Mal bauen wir auf den Sockets auf â von der rohen Verbindung zur echten verteilten Anwendung.
Prof. Dr. Alexandra Mikityuk
HTW Berlin · Verteilte Systeme
© 2026 HTW Berlin · Verteilte Systeme