05.11.2013 Aufrufe

Zahn - Unix-Netzwerkprogramminerung mit Threads, Sockets und SSL

Zahn - Unix-Netzwerkprogramminerung mit Threads, Sockets und SSL

Zahn - Unix-Netzwerkprogramminerung mit Threads, Sockets und SSL

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

5.2 Iterative Server 259<br />

49–62<br />

64–72<br />

75–80<br />

82–87<br />

Jetzt beginnt die Verarbeitungsschleife für die Clientanfragen: Der Server<br />

wartet als erstes <strong>mit</strong> accept() auf eine neue Verbindung. Auch beim Aufruf<br />

der accept()-Funktion arbeitet der Server durch den Einsatz der generischen<br />

Socket-Adreßstruktur struct sockaddr_storage übrigens protokollunabhängig<br />

(vgl. dazu Abschnit 4.3.2). Der Server kann also sowohl <strong>mit</strong> IPv4-<br />

als auch <strong>mit</strong> IPv6-basierten TCP-Verbindungen umgehen.<br />

Sollte accept() <strong>mit</strong> einem Rückgabewert kleiner 0 zurückkehren, so kann dies<br />

daran liegen, daß die Funktion vom SIGTERM-Signal unterbrochen wurde. In<br />

diesem Fall wurde die globale Variable daemon_exit von der Signalbehandlungsroutine<br />

sig_term() auf den Wert 1 gesetzt <strong>und</strong> das Programm bricht<br />

<strong>mit</strong> break aus der Verarbeitungsschleife aus. In allen anderen Fällen wird der<br />

aufgetretene Fehler über den Syslog-Dienst protokolliert <strong>und</strong> das Programm<br />

springt zum nächsten accept(). 5<br />

Sobald eine TCP-Verbindung besteht, kümmert sich die in Abschnitt 5.2.2<br />

besprochene Funktion handle_client() um die weitere Verarbeitung. Beim<br />

Aufruf wird der Funktion als einziges Argument der Socketdeskriptor für<br />

die frisch etablierte Clientverbindung übergeben. Nach der Rückkehr aus<br />

handle_client() wird die Verbindung zum Client wieder abgebaut.<br />

Am Programmende gibt der Dæmon noch die er<strong>mit</strong>telten CPU-Statistiken<br />

aus, entfernt die PID-Datei <strong>und</strong> beendet sich schließlich durch exit().<br />

5.2.2 Clientbehandlung<br />

10–31<br />

33–55<br />

Die handle_client()-Funktion aus Beispiel 5.10 ist für alle in den kommenden<br />

Abschnitten vorgestellten Servervarianten identisch. Sie wurde deshalb in<br />

eine eigenenständige Programmdatei ausgelagert.<br />

Die vom Server verursachte Nutzlast besteht darin, nach dem Prinzip Sieb des<br />

Eratosthenes die vom Client geforderte Menge an Primzahlen zu bestimmen.<br />

Die Hilfsfunktion eratosthenes() übernimmt diese Aufgabe <strong>und</strong> berechnet<br />

alle Primzahlen bis zur maximalen Größe num. Das Ergebnis der Berechnungen<br />

wird am Ende der Funktion sofort wieder verworfen.<br />

Die Funktion handle_client() erwartet als einzigen Parameter den Socketdeskriptor<br />

der bereits aufgebauten TCP-Verbindung zum anfragenden Client.<br />

handle_client() schickt zunächst <strong>mit</strong>tels writen() einen Grußtext an den<br />

5 In den meisten Beispielprogrammen aus der Literatur wird stattdessen bei einem<br />

accept()-Fehler der Dienst beendet. Dies kann fatale Auswirkungen haben, denn<br />

accept() kann durchaus auch aus nicht-abbruchwürdigen Gründen <strong>mit</strong> einem<br />

Rückgabewert kleiner Null zurückkehren. So liefert accept() u. U. den ”<br />

Fehler“<br />

ECONNABORTED, wenn eine frisch aufgebaute Verbindung von Clientseite bereits<br />

wieder beendet wurde, noch bevor beim Server der accept()-Aufruf zurückgekehrt<br />

ist. Ein geschickt programmierter Client könnte da<strong>mit</strong> einen Server ohne<br />

Not zum Abbruch <strong>und</strong> da<strong>mit</strong> zur Aufgabe seines Dienstes bewegen.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!