lecture-notes/inputs/network_programming/sockets.tex

725 lines
24 KiB
TeX
Raw Normal View History

2022-02-15 20:57:33 +01:00
\subsection{Einführung zu Sockets}
Das \vocab[Generisches API]{Generische API}
\begin{itemize}
\item unterstützt \vocab[Nachrichten-orientiert]{Nachrichten-orientierte} und \vocab[Verbindungs-orientiert]{Verbindungs-orientierte} Kommunikation.
\item ist betriebssystemunabhängig
\item nutzt I/O Dienste des Betriebssystems
\item unterstützt verschiedene Protokollfamilien
\item ist unabhängig von der konkreten Adress-Repräsentation der kommunizierenden Endpunkte
\item unterstützt ggf.~manche Clients und Server auf spezielle Weise
\end{itemize}
Es gibt verschiedene APIs für den Zugriff auf TCP / IP:
\begin{itemize}
\item (Berkeley-) Sockets, diese werden wir uns genauer ansehen
\item TLI (System V Transport Layer Interface)
\item XTI (X/Open Transport Interface)
\item Winsock
\item MacTCP
\item Asio C++ Library (plattformunabhängig)
\end{itemize}
\subsubsection{Benötigte Funktionen des Network API}
Ein Network API stellt grundsätzlich Folgendes zur Verfügung:
Vorbereitung:
\begin{itemize}
\item Identifikation der beiden Endpunkte der Kommunikation
\item Verbindungsaufbau (ggfs.~kein Verbindungsaufbau, d.h.~verbindungslos)
\item Warten auf eingehende Verbindungswünsche (typisch für Server)
\end{itemize}
Datentransferphase:
\begin{itemize}
\item Senden und Empfangen von Daten
\item Fehlerbehandlung
\end{itemize}
Nachbereitung:
\begin{itemize}
\item Ordentlicher Abbau einer Verbindung
\item ggf.~Fehlerbehandlung
\end{itemize}
\subsubsection{Berkeley-Sockets}
\vocab{Berkeley-Sockets} stammen ursprünglich aus Berkeley-Unix, mittlerweile werden sie einfach Sockets genannt.
Diese werden wir uns genauer ansehen.
Ein Socket ist eine Datenstruktur innerhalb eines Programms und stellt eine \emph{abstrakte Repräsentation} eines kommunizierenden Endpunktes
dar.
Sockets sind durch Systemfunktionen implementiert und arbeiten ähnlich wie andere Unix I/O-Dienste.
Sockets unterstützen verschiedene Protokollfamilien und sind insbesondere unabhängig von der konkreten Adressdarstellung.
\subsubsection{Socket framework}
Mit einem Socket können wir vom User Space aus auf Funktionalität des Kernel Space, insbesondere
TCP oder UDP, und damit indirekt auf IP und Netzwerktreiber zugreifen. Der direkte Zugriff auf \ac{ip} benötigt in der Regel
privilegierte Rechte.
\subsubsection{Unix Descriptor Table}
Unix führt eine \vocab{Descriptor Table}, die jeweilige Datenstrukturen enthält (siehe auch \autoref{descriptortable}).
Dieser kann sowohl Dateideskriptoren (wie bereits kennengelernt), als auch Socket
Descriptoren enthalten.
Ein \vocab{Socket Descriptor} ist ein normaler File Descriptor, dessen Eintrag in der Descriptor Table jedoch eine Address-Family, einen Service, Local IP, Remote IP, Local Port und Remote Port enthält.
\subsubsection{Socket Domain Families}
Die \vocab{Protokollfamilie} eines Sockets muss bei Initialisierung festgelegt werden.
Es gibt die folgenden Schlüssel:
\begin{itemize}
\item \vocab{Internet Domain Sockets}, verfügbar mittels \ccintro{AF_INET}
\item \vocab{Unix Domain Sockets}, mittels \ccintro{AF_UNIX} oder \ccintro{AF_LOCAL}
\item \vocab{Novell IPX}, mittels \ccintro{AF_IPX}
\item \vocab{AppleTalk} (buuuuh!), mittels \ccintro{AF_APPLETALK}
\end{itemize}
\begin{remark}
Beachte, dass alle diese macros mit \code{AF_} beginnen, dies steht für \enquote{address family}.
Mittlerweile wird allerdings nicht mehr zwischen Protokollfamilien und Adressfamilien unterschieden.
\end{remark}
\subsubsubsection{Service Typ eines Sockets}
Ein Socket kann einen von drei Typen haben
\begin{description}
\item[Stream]
Schlüssel \ccintro{SOCK_STREAM}, Verbindungs- und Byte-Stream orientiert.
Unter \code{AF_INET} wird \ac{tcp} eingesetzt.
\item[Datagram]
Schlüssel \ccintro{SOCK_DGRAM}, verbindungslos und unzuverlässig.
Unter \code{AF_INET} wird \ac{udp} eingesetzt.
\item[Direktzugriff]
Schlüssel \ccintro{SOCK_RAW}.
Dieser umgeht das Transportprotokoll und greift direkt auf das Kommunikationsprotokoll (im Fall von \code{AF_INET} \ac{ip}) zu.
In der Regel werden spezielle Rechte benötigt.
\end{description}
Die letzte Möglichkeit besteht zwar, erfordert allerdings viel aufwand,
weil IP selbst nicht ports spezifiziert (das machen \ac{udp} / \ac{tcp} ),
und dies somit manuell geschehen muss.
Anwendung findet dies in speziellen Routern oder eigenen Protokollen.
\autoref{tab:protokollfamilien} zeigt die Protokollfamilien und den Service-Typ eines sockets,
und die entsprechenden Protokolle, die verwendet werden.
\begin{table}[htpb]
\centering
\begin{tabular}{c | c | c | c | c | c}
& \cc{AF_INET} & \cc{AF_INET6} & \cc{AF_LOCAL}, \cc{AF_UNIX} & \cc{AF_ROUTE} & \cc{AF_KEY} \\
\hline
\cc{SOCK_STREAM} & \ac{tcp} & \ac{tcp} & Ja & & \\
\cc{SOCK_DGRAM} & \ac{udp} & \ac{udp} & Ja & & \\
\cc{SOCK_RAW} & IPv4 & IPv6 & & Ja & Ja
\end{tabular}
\caption{Kombinationsmöglichkeiten von Protokollfamilie und Socket Type für Internetprotokolle}
\label{tab:protokollfamilien}
\end{table}
\subsubsubsection{Erzeugung eines Sockets}
Vergleiche für die beiden Parameter auch \autoref{tab:protokollfamilien}
Das Erzeugen eines sockets geschieht mit \ccintro{socket()}.
\begin{lstlisting}[gobble=2]
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
// domain gibt die Protokollfamilie an: AF_INET, AF_INET6, AF_LOCAL, ...
// type gibt SOCK_STREAM, SOCK_DGRAM oder SOCK_RAW an
// protocol setzt spezielle Werte im Protokoll-feld
// wird aber bei TCP und UDP automatisch behandelt, und deswegen auf 0 gesetzt.
// Rueckgabewerte: ein socketdeskriptor, -1 im Fehlerfall
\end{lstlisting}
Solch ein Socket stellt nun abstrakte Ressourcen bereit, um zu kommunizieren,
kümmert sich jedoch noch nicht um Adressierung etc.
Um einen Socket zu benutzen, um empfangsbereit zu sein, verwendet man:
\begin{lstlisting}[gobble=2]
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
// sockfd: der behandlete socket file deskriptor
// myaddr: ein Zeiger auf eine (generische) Adresse
// addrlen: Laengenangabe des Adress-structs unter @myaddr
// gibt -1 im Fehlerfall zurueck, 0 sonst
\end{lstlisting}
\subsubsubsection{Socket-Adressen}
Ein \ccintro{struct sockaddr} sieht wie folgt aus:
\begin{lstlisting}[gobble=2]
typedef uint16_t sa_family_t;
struct sockaddr {
sa_family_t sa_family; // address family
char sa_data[14]; // up to 14 bytes of direct address
}
\end{lstlisting}
% \todoquestion{sehe ich das richtig, dass sowohl der socket als auch der addr die adressfamilie bekommen müssen?} Ja. Siehe https://stackoverflow.com/questions/5263262/why-does-struct-sockaddr-contain-a-address-family-field
\begin{remark}
Auf manchen Betriebssystemen gibt es noch ein \ccintro[sin_len]{uint8_t sin_len}
im \cc{struct sockaddr}, das interessiert uns jedoch ersteinmal nicht.
\end{remark}
\begin{table}[htpb]
\centering
\caption{Typen}
\label{tab:types}
\begin{tabular}{lll}
\textbf{Datentyp} & \textbf{Beschreibung} & \textbf{Header} \\
\hline
\ccintro{int8_t}, \ccintro{int16_t} & signed integer ($8 / 16 / 32 / 64$ bit) & \code{sys/types.h}\\
\ccintro{int32_t},\ccintro{int64_t} \\
\ccintro{uint8_t}, \ccintro{uint16_t} & unsigned integer ($8 / 16 / 32 / 64$ bit) & \code{sys/types.h}\\
\ccintro{uint32_t}, \ccintro{uint64_t}\\
\hline
\multirow{2}*{\ccintro{sa_family_t}} & address family of socket address structure,& \multirow{2}*{\code{sys/socket.h}} \\
& normally \cc{uint16_t}& \\
\multirow{2}*{\ccintro{socklen_t}} & length of socket address structure,&\multirow{2}*{\code{sys/socket.h}} \\
& normally \cc{uint32_t} &\\
\hline
\ccintro{in_addr_t} & IPv4 address, normally \cc{uint32_t} & \code{netinet/in.h} \\
\ccintro{in_port_t} & TCP or UDP port, normally \cc{uint16_t} & \code{netinet/in.h}\\
\ccintro{struct in6_addr} & IPv6 address & \code{netinet/in.h}
\end{tabular}
\end{table}
Die Adressen der Internet-Protokollfamilie sehen wie folgt aus:
\begin{lstlisting}
struct in_addr {
in_addr_t s_addr; // 32 bit IPv4 address
}
struct sockaddr_in {
sa_family_t sin_family; // here: AF_INET
in_port_t sin_port; // 16-bit TCP / UDP port number. network byte order!
struct in_addr sin_addr; // 32 bit IPv4 address. network byte order!
char sin_zer[8]; // unused, total size 16 bytes
};
\end{lstlisting}
Das \cc{struct sockaddr_in} wird somit auf ein \cc{struct sockaddr} gecastet,
um an \cc{socket()} übergeben zu werden.
Unser socket enthält somit bereits IP-Adresse, Protokoll-Type und Portnummer,
um einen verbindungsaufbau zu ermöglichen.
\subsubsubsection{Network byte order}
Die Werte \cc{sin_port} sowie \cc{sin_addr} müssen in der sogenannten
\vocab{network byte order} abgelegt sein.
Das liegt daran, dass verschieden Systeme \vocab{Little Endian} oder \vocab{Big Endian}
benutzen können, und wir für die Netzwerkübertragung eine einheitliche Darstellung benötigen.
Die \vocab{Host Byte Order} ist die byte order des hosts.
\begin{definition}
Die \vocab{Network Byte Order} ist als Big Endian definiert.
\end{definition}
\begin{warning}
Beim spezifizieren von Netzwerk-Parametern müssen wir also auf die Endianness achten!
\end{warning}
Hierzu stehen folgende Hilfsfunktionen zur Verfügung:
\begin{lstlisting}
uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);
uint16_t ntohs(uint16_t netshort);
uint32_t ntohl(uint32_t netlong);
\end{lstlisting}
Hierzu werden die Abkürzungen \emph host, \emph network, \emph short und \emph long benutzt.
\subsubsubsection{Komplettbeispiel: Öffnen eines sockets mit \ac{udp}}
\begin{lstlisting}[gobble=2]
int fd, err;
struct sockaddr_in addr;
fd = socket(AF_INET,SOCK_DGRAM,0);
if (fd<0) { ... } // error handling
addr.sin_family = AF_INET;
addr.sin_port = htons(4711);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
err = bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
if (err<0) { ... } // error handling
\end{lstlisting}
\begin{remark}
Das macro \ccintro{INADDR_ANY} gibt an, dass das Betriebssystem die IP-Adresse
automatisch bestimmt, und zwar die des eigenen Rechners.
Analog kann auch die Portnummer als 0 spezifiziert werden,
dann kümmert sich das Betriebssystem automatisch darum,
einen geeigneten Port zuzuweisen. Diese ist $> 1023$.
\end{remark}
\subsubsubsection{Weitere Socket-Adress-Strukturen}
Die structs for die IPv6-Familie oder für Unix-Domain Sockets können auch
deutlich länger als 16 Byte sein. Deswegen ist die übergabe der Länge
des struct essentiell.
\subsubsubsection{Kommunikation über Sockets mit \ac{udp}}
Wir kennen bereits \code{socket()} und \code{bind()}.
Um nun zwischen Client und Server zu kommunizieren,
führt üblicherweise nur der Server ein \code{bindto()} aus,
und wartet mit \code{recvfrom()} auf eingehende Datagramme.
Mit \code{sendto()} können nun sowohl client als auch Server
Datagramme verschicken.
Auch der Client kann nun mit \code{recvfrom()} Daten empfangen.
Typischerweise befinden sich nun Client und Server in einem
Zyklus aus \vocab{Empfangen}, \vocab{Verarbeiten}, \vocab{Beantworten}.
Mit \code{close()} kann der Socket am Ende geschlossen werden.
\begin{warning}
Es ist sehr wichtig, den Socket am Ende wieder zu schließen,
sonst bleibt der Port auch über das Programmende eine
gewisse Zeit im kernelspace, weil Sockets (grundsätzlich)
kernel-persistence besitzen.
Der Kernel schließt den socket allerdings nach einer
gewissen Zeit ($\approx$ 1min.), das kann jedoch bereits
nervig sein.
\end{warning}
\todoquestion{kann ich einen bestehenden socket übernehmen?}
\subsubsubsection{\code{sendto()}}
Der Aufruf von \code{sendto()} hat die Signatur:
\begin{lstlisting}[gobble=2]
#include <sys/types.h>
#include <sys/socket.h>
int sendto(int sockfd, const void *buff, size_t nbytes,
int flags, const struct sockaddr *to, socklen_t tolen);
// sockfd: file descriptor des sockets
// buff: zu sendender Buffer
// nbytes: Anzahl zu sendender Bytes
// flags: Optionen, spaeter behandlet
// to: Zeiger auf Zieladress-Struktur
// tolen: Laenge der Ziel-Adressstruktur
// return: -1 bei Fehler, sonst Anzahl gesendeter Bytes
\end{lstlisting}
\begin{example}[Senden von Daten]
\label{ex:senden-von-daten-udp}
\begin{lstlisting}[gobble=2]
// nimm an, dass wir den socket sockfd bereits erstellt haben
// (nicht zwingend gebinded)
char msg[64];
int err;
struckt sockaddr_in dest;
strcpy(msg, "hello, world!");
dest.sin_family = AF_INET;
dest.sin_port = htons(4711);
dest.sin_addr.s_addr = inet_addr("130.37.193.13");
err = sendto(
sockfd, msg, strlen(msg) + 1, 0,
(struct sockaddr*) &dest, sizeof(struct sockaddr_in)
);
if (err < 0) { ... } // Fehlerbehandlung
...
\end{lstlisting}
\end{example}
\begin{remark}
Man sollte auf jeden Fall den Fehlerstatus überprüfen.
Die Anzahl der gesendeten bytes sollte vor allem dann
überprüft werden, wenn man potenziell zu viele bytes
gesendet hat.
\end{remark}
\subsubsubsection{Hilfsfunktionen für \ac{ip}-Adressen}
\ac{ip}-Adressen werden zur Verbesserung der Lesbarkeit üblicherweise
als \vocab{Dotted-Decimal-Schreibweise} durch 4 Dezimalzahlen dargestellt,
die jeweist 8 bit, also Zahlen von $0$ bis $255$.
Es stehen zwei Hilfsfunktionen zur Verfügung:
\begin{lstlisting}
#include <arpa/inet.h>
in_addr_t inet_addr(const char *dotted); // Conversion of dotted address to in_addr_t
char *inet_ntoa(struct in_addr network); // Conversion of in_addr_t to dotted
\end{lstlisting}
\begin{warning}
Der Aufruf von \code{inet_ntoa} returned die Adresse in einem
statisch allokierten Buffer, der bei weiteren Aufrufen überschrieben wird.
Damit ist der Aufruf insbesondere \alert{nicht} thread-safe.
\end{warning}
\begin{remark}[Der Vollständigkeit halber]
Es gibt auch \code{inet_aton(const char *cp, struct in_addr *inp)},
die ebenfalls von der dotted schreibweise konvertiert,
und das Ergebnis im entsprechenden struct ablegt.
Man hätte also in \autoref{ex:senden-von-daten-udp} auch folgendes schreiben
können:
\begin{lstlisting}
// dest.sin_addr.s_addr = inet_addr("130.37.193.13");
char dest_addr[15] = "130.37.193.13";
inet_aton( &dest_addr, &dest.sin_addr );
\end{lstlisting}
\end{remark}
\subsubsubsection{\code{recvfrom()} - Empfangen von Daten}
\begin{lstlisting}
#include <sys/types.h>
#include <sys/socket.h>
int recvfrom(int sockfd, void *buff, size_t nbytes,
int flags, struct sockaddr *from, socklen_t *fromlen);
// sockfd: File Deskriptor des sockets
// buff: buffer fuer zu empfangende daten
// nbytes: laenge des buffers
// flags: optionen, standard 0 (weiter spaeter)
// from: zeiger auf socket-adress-strucktur mit quelladresse (port + ip-adresse)
// fromlen: Zeiger auf lange der adress-struktur.
//return: -1 bei fehler, sonst laenge der empfangenen daten
// das argument fromlen ist ein value-return argument, d.h.
// es wird bei erfolgreichem funktionsaufruf geupdatet,
// und zwar auf die tatsaechliche laenge der
// struct sockaddr *from struktur
// war diese laenger als die urspruengliche eingabe von fromlen
// wird die from - addresse abgeschnitten,
// und fromlen auf den entsprechend groesseren wert
// gesetzt
\end{lstlisting}
\begin{remark}
Mit Quelle ist hierbei nicht gemeint, dass man \emph{nur} Datagramme
von dieser Quelle akzeptiert.
Diese ist unspezifiziert, die Quelladresse wird jedoch
im \code{struct sockaddr *from} abgelegt.
Der Aufruf von \code{recvfrom()} blockiert (im Normalfall),
bis Daten empfangen wurden.
Man kann \code{from} und \code{fromlen} auch auf \code{NULL} setzen,
dann wird die Sender-Adressstruktur nicht gespeichert.
Stattdessen kann man auch einfach \code{recv()} aufrufen,
das die beiden argumente nicht erwartet.
\end{remark}
\begin{example}[Beispiel von \code{recvfrom()}]
\begin{lstlisting}[gobble=4]
char msg[64];
int len, flen;
struck sockaddr_in from;
flen = sizeof(struct sockaddr_in);
len = recvfrom(
sockfd, msg, sizeof(msg), 0,
(struckt sockaddr*) &from, &flen);
if (len < 0) { ... } // fehlerbehandlung
printf("Received %d bytes from host %s with port %d: %s",
len, inot_ntoa(from.sin_addr), ntohs(from.sin_port), msg);
\end{lstlisting}
\end{example}
\begin{warning}
Das obige Beispiel ist natürlich Sicherheitstechnisch völlig grauenhaft.
Wenn wir nicht gerade einen string bekommen haben, könnte das
printen mittels '\%s' der erhaltenen nachricht unseren gesamten speicher
leaken / segfaulten / \ldots
\end{warning}
\begin{warning}
Die manpage behauptet, dass überschüssige Daten eines Datagrammes,
das zu lange für den angegebenen Buffer ist, je nach sockettyp
verworfen werden können.
In der Vorlesung wurden 2 Euro verwettet, weil fälschlicherweise
geclaime wurde,
dass dies bei UDP nicht der Fall ist,
mit einem weiteren \code{recvfrom()} kann dann der Rest der Nachricht
abgerufen werden.
UDP verliert überschüssige Daten.
\end{warning}
\subsubsubsection{Schließen eines sockets}
Funktioniert gleich wie bei files:
\begin{lstlisting}
#include <unistd.h>
int close(int sockfd);
\end{lstlisting}
\subsection{Kommunikation über Sockets mit \ac{tcp}}
Da \ac{tcp} ein Verbindungsorientiertes Protokoll ist,
sieht die Kommunikation etwas anderst aus.
Für einen Server stehen \code{listen()} und \code{accept()}
zur Verfügung, um auf eingehende Verbindungswünsche zu hören,
und sie zu akzeptieren.
Der Client verwendet \code{connect()}, um eine Verbindung aufzubauen.
Besteht die Verbindung, so stehen \code{read()} und \code{write()}
auf beiden Seiten zur Verfügung.
Mit \code{close()} schließt der Client die Verbindung,
dies kann beim server beim nächsten \code{read()} erkannt werden.
\todoimg{3.2 - 70}
\subsubsubsection{Servervorbereitung bei \ac{tcp}}
Nachdem ein Socket mit \code{socket()} erstellt und mit \code{bind()}
gebinded wurde, versetzt man ihn mit \code{listen()} in einen aktiven
Zustand, d.h.~dieser wartet auf Verbindungsaufbauten
\begin{lstlisting}
#include <sys/socket.h>
int listen(int sockfd, int backlog);
// sockfd: socket file deskriptor
// backlog: maximale anzahl gleicher verbindungsaufbauten. typisch: 5
//return: -1 bei fehler, 0 bei erfolg
\end{lstlisting}
\begin{remark}
Der Parameter \code{backlog()} beschränkt nicht die Anzahl der möglichen
Verbindungen, nur die Anzahl derjenigen, die
eine Verbindung aufbauen, aber noch nicht akzeptiert wurden.
\end{remark}
\subsubsubsection{Clientvorbereitung bei \ac{tcp}}
Nachdem der client mit \code{socket()} einen socket erstellt hat,
kann er mit \code{connect()} einen Verbindungsaufbau beginnen.
\begin{lstlisting}
#include <sys/types.h>
#incldue <sys/socket.h>
int connect(int sockfd. const struct sockaddr *serv_addr, socklen_t addrlen);
// sockfd: sockt file deskriptor
// serv_addr: zeiger auf adresse des servers (die enthaelt ip + port)
// addrlen: leange der adress struktur
// return: -1 bei fehler, 1 bei erfolg
\end{lstlisting}
\subsubsubsection{Server: Akzeptieren von Verbindungen bei \ac{tcp}}
Hierzu steht \code{accept()} zur Verfügung.
\begin{lstlisting}
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
// sockfd: socket file deskriptor
// addr: zeiger auf adress-struktur
// addrlen: laenge der adress-struktur
// return: *neuer* socket-deskriptor, der die verbindung darstellt,
// -1 bei Fehler
\end{lstlisting}
Auch hier wird \code{addrlen} als value-return dynamisch angepasst.
\begin{example}
\begin{lstlisting}[gobble=4]
int sockfd, newsock, res;
sockaddr_in client_addr;
socklen_t addrlen;
res = listen(sockfd,5);
if (res<0) { ... } // fehlerbehandlung
addrlen = sizeof(struct sockaddr_in);
newsock = accept(sockfd,(struct sockaddr *) &client_addr, &addrlen);
if (newsock < 0) { ... }
else {
printf("Received connection from %s!\n", inet_ntoa(client_addr.sin_addr);
}
\end{lstlisting}
\end{example}
\subsubsubsection{Schwebezustand im Verbindungsaufbau}
\todoimg{3.2 - s.76}
Führt ein Client \code{connect()} aus, so findet ein sog. 3-Wege-Handshake
statt.
Nach dem 2. Handshake kehrt \code{connect()} zurück.
Nach dem 3. Handshake kehrt ein evtl. vorhandener \code{accept()}
Aufruf unmittelbar zurück.
\begin{remark}
Wir werden später betrachten, wie ein Server mit mehreren
Verbindungen umgehen kann.
\end{remark}
\subsubsubsection{Senden von Daten bei \ac{tcp}}
Der Aufruf ist ähnlich wie der von \code{sendto()} im Falle von \ac{udp}.
\begin{lstlisting}
#include <unistd.h>
ssize_t write(int sockfd, const void *buff, size_t count);
// sockfd: File deskriptor des sockets
// buff: zu sendender buffer
// count: laenge der zu sendenden daten
// return: -1 bei fehler, sonst anzahl gesendeter bytes
\end{lstlisting}
\begin{remark}
Die Anzahl der gesendeten bytes kann durchaus weniger als \code{count} sein.
Mas sollte deswegen immer den Rückgabewert prüfen und ggfs.~restliche Daten
erneut senden.
\end{remark}
\subsubsubsection{Empfangen von Daten bei \ac{tcp}}
Hierzu gibt es \code{read()}
\begin{lstlisting}[gobble=2]
#include <unistd.h>
ssize_t read(int sockfd, void *buff, size_t count);
// sockfd: file deskriptor des sockets
// buff: buffer, in den gelesen wird
// count: groesse des buffers
// return: -1 bei felher
// 0: sonderfall: kennzeichnung von end of file
// >0 anzahl der empfangenen bytes
\end{lstlisting}
\begin{remark}
Der Rückgabewert von \code{read()} kann natürlich kleiner als \code{count()} sein.
Der return value $0$ für EOF signalisiert den Wunsch auf Verbindungsabbau,
d.h.~der Kommunikationspartner hat \code{close()} aufgerufen.
\end{remark}
\subsubsubsection{Aufruf von \code{close()}}
\code{close()} \vocab{markiert} einen Socket zum schließen.
Erst wenn alle existierenden file-deskriptoren des sockets
geschlossen wurden, schließt das Betriebssystem diesen tatsächlich.
Bereits an den socket übergebene, aber von \ac{tcp} noch nicht
versendete Daten gehen beim schließen \emph{nicht} verloren.
\begin{remark}
Es ist möglich, dass ein Prozess mit bestehender \ac{tcp}-Verbindung
\code{fork()} aufruft, und der parent die verbindung schließt.
Das child kann weiterhin die Verbindung nutzen.
\end{remark}
\subsubsubsection{Alternative zu \code{close()}: \code{shutdown()}}
Mit \code{shutdown()} kann man einseitig eine Verbindung schließen.
\begin{lstlisting}
#include <sys/socket.h>
int shutdown(int sockfd, int howto);
\end{lstlisting}
\code{howto} ist hierbei eines von \code{SHUT_RD}, \code{SHUT_WR} oder \code{SHUT_RDWR},
die kanonisch nur read, nur write, oder beide Teile der Verbindung schließen können.
\subsubsection{Sockets in Rust}
Wir geben einen groben Überblick über sockets in Rust,
um die Analogien auch über Programmiersprachen hinweg zu geben.
\subsubsection{Übersicht der Adressen bei \ac{udp}}
\todoimg{3.2 - 93, 94}
\subsubsection{Übersicht der Adressen bei \ac{tcp}}
\todoimg{3.2 - 95, 96}
\subsubsection{Hilfsfunktionen bei \ac{tcp} und \ac{udp}}
\ac{udp} und \ac{tcp} bestimmen die Adressen in der Regel automatisch,
dies umfasst
\begin{itemize}
\item Portnummer beim Client
\item IP-Adresse beim Client
\item IP-Adresse beim Server
\item ggfs.~Portnummer beim SEvrer
\end{itemize}
Die konkreten Adressen kann man mit \code{getsockname()} und \code{recvmsg()}
selbst auslesen.
Dies sollen hier jedoch nicht näher betrachtet werden.