Browse Source

Add chapter 09.

master
paulusja 1 year ago
parent
commit
13a8605f28

+ 404
- 0
09kapitel/091 Dateien.ipynb View File

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Software Entwicklung \n",
"\n",
"## Kapitel 9: IO\n",
"\n",
"Unter *IO* (Input/Output) versteht man alle Mechanismen,\n",
"die mit dem Ausleiten von Daten aus einem Programm\n",
"bzw. dem Einlesen von Daten in ein Programm zusammenhängen."
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### 9.1 Zeichenkodierung\n",
"\n",
"Möchte ein Programm Daten senden (z.B. in eine Datei\n",
"oder über eine Netzwerkverbindung) oder diese empfangen,\n",
"werden letztendlich Bytes übertragen. Handelt es sich bei den\n",
"Daten um Text - also lesbare Zeichen - so muss durch eine\n",
"Zeichenkodierung (engl. *encoding*) festgelegt werden,\n",
"wie dieser Text auf Bytes abgebildet wird.\n",
"\n",
"Ein sehr übliches Kodierungsschema ist *UTF-8*. Darin werden\n",
"die Zahlen 0 bis 127 analog zum alten ASCII-Standard\n",
"insbesondere für grundlegende lateinische Zeichen in\n",
"Groß- und Kleinschrift verwendet. Alle übrigen Zeichen wie\n",
"z.B. deutsche Umlaute, chinesische Schriftzeichen,\n",
"Emojis etc. werden durch größere Zahlen ggf. mit mehreren\n",
"Bytes codiert. Die Zuordnung der Zahlen zu den Zeichen\n",
"ist durch den [*Unicode*-Standard](http://www.unicode.org/)\n",
"festgelegt."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Möchte man eine Python-Zeichenkette in eine Unicode-Bytefolge\n",
"übertragen, so kann dafür die Methode <code>encode</code> der Klasse\n",
"*str* (String) verwendet werden."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"text = \"Nürnberg ist schön\"\n",
"print(f\"Länge {len(text)}\")\n",
"utf8 = text.encode(\"utf-8\")\n",
"print(utf8)\n",
"print(f\"Länge {len(utf8)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"Das vorangestellte <code>b</code> signalisiert, dass es sich\n",
"hier um eine Bytefolge handelt."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"print(type(utf8))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Eine solche Bytefolge kann auch wieder in einen\n",
"Textstring verwandelt werden. Dazu besitzt die\n",
"Klasse *bytes* die Methode <code>decode</code>."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"decoded_text = utf8.decode(\"utf-8\")\n",
"print(decoded_text)\n",
"print(f\"Länge {len(decoded_text)}\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### 9.2 Dateien\n",
"\n",
"Unter *Textdateien* verstehen wir Dateien, die\n",
"mit einem Texteditor erzeugt und bearbeitet werden können.\n",
"Der Inhalt sind lesbare Zeichen, die meist\n",
"in Zeilen organisiert sind. Um sie auf einem\n",
"Speichermedium abzulegen, müssen die Zeichen\n",
"in Bytes konvertiert bzw. beim Lesen\n",
"rückübertragen werden.\n",
"\n",
"*Binärdateien* sind Dateien, für die keine Kodierung\n",
"stattfinden soll (z.B. Bilder).\n",
"\n",
"Python besitzt bereits im Standard Funktionen, Klassen und Methoden,\n",
"die das Lesen und Schreiben von Dateien sowie das Übertragen\n",
"von Text in Bytes (und zurück) unterstützen."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Einstiegspunkt ist die Built-In-Funktion <code>open</code>, die ein\n",
"Dateiobjekt zurückliefert. Die Parameter von <code>open</code> sind\n",
"der *Dateiname* (ggf. inkl. Pfad) und der *Bearbeitungsmodus*\n",
"sowie weitere, weniger gebräuchliche optionale Parameter.\n",
"\n",
"\n",
"| *Bearbeitungsmodus* | *Bedeutung* |\n",
"|:--------------------:|----------------------------------------------------|\n",
"| 'r' | Die Datei wird gelesen (muss bereits existieren) |\n",
"| 'w' | Die Datei wird geschrieben (vorhandene Datei wird überschrieben) |\n",
"| 'a' | Die Datei wird geschrieben (neuer Inhalt wird angehängt) |\n",
"| 'r+' | Die Datei wird gelesen und geschrieben |\n",
"\n",
"Standardmäßig finden die Lese- und Schreiboperationen mit der Standard-Kodierung des verwendeten Betriebssystems statt. Soll die Kodierung unterbleiben, muss an den Bearbeitungsmodus ein <code>'b'</code>\n",
"(für binär) angehängt werden."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
},
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"f = open(\"091a Textdatei\", \"r\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Das auf diese Weise erhaltene Dateiobjekt kann für (je nach\n",
"Bearbeitungsmodus) für das Lesen und Schreiben benutzt werden.\n",
"Die Methode <code>read</code> ohne Angabe eines Parameter\n",
"liest den gesamten Inhalt der Datei ein\n",
"(Vorsicht: nur bei kleinen Dateien ratsam, da speicherintensiv)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"content = f.read()\n",
"print(content)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Jedes geöffnete Dateiobjekt muss auch wieder geschlossen werden,\n",
"da andernfalls Betriebssystemressourcen dauerhaft belegt bleiben."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"print(f.closed)\n",
"f.close()\n",
"print(f.closed)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Sollte eine Textdatei in einer anderen Kodierung als die Standard-Kodierung vorliegen, kann die gewünschte Kodierung mittels des Parameters <code>encoding</code> angegeben werden. Mit <code>encoding=None</code> wird wieder die Standard-Kodierung gewählt, was dem Standardwert und damit dem Weglassen des Parameters entspricht. Im folgenden Beispiel wird eine Textdatei geladen, die im UTF-8-Format vorliegt. Die Standard-Kodierung auf Windows weicht allerdings davon ab, wie man an den Umlauten erkennen kann."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"f = open(\"utf8_text\", \"r\", encoding=None)\n",
"content = f.read()\n",
"print(content)\n",
"f.close()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### 9.3 Kontextmanager\n",
"\n",
"Die strenge Verpflichtung, jede Datei auch zu schließen, ist\n",
"gelegentlich nicht einfach zu erfüllen. Falls z.B. eine\n",
"Exception auftritt und die Abarbeitungsreihenfolge\n",
"abgebrochen wird, ist trotzdem *close* aufzurufen."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
},
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"try:\n",
" f = open(\"091a Textdatei\", \"r\")\n",
" z = 1 / 0\n",
" # f.close() würde nicht erreicht!\n",
"except:\n",
" print(\"Fehler!\")\n",
"finally:\n",
" f.close()\n",
"print(f.closed)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Python bietet für dieses Problem den *Kontextmanager* an. Er\n",
"initialisiert einen *Kontext* für ein Objekt, führt einen\n",
"Codeblock in diesem Kontext aus und räumt beim Verlassen\n",
"des *Kontext* belegte Ressourcen auf.\n",
"\n",
"Das Schlüsselwort für den Beginn eines *Kontext* ist <code>with</code>."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"091a Textdatei\", \"r\") as f:\n",
" print(f.read())\n",
" print(f.closed)\n",
"\n",
"print(f.closed)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Wie ist das realisiert? Tatsächlich nutzt der\n",
"*Kontextmanager* die beiden *dunder*-Methoden\n",
"<code>\\_\\_entry\\_\\_</code> und <code>\\_\\_exit\\_\\_</code>.\n",
"Die Methode <code>\\_\\_entry\\_\\_</code> wird beim Betreten des\n",
"Kontext aufgerufen, die Methode <code>\\_\\_exit\\_\\_</code> beim\n",
"Verlassen oder beim Auftreten einer nicht behandelten Exception.\n",
"\n",
"Beim Datei-Objekt von Python wird in der\n",
"<code>\\_\\_exit\\_\\_</code>-Methode sichergestellt, dass die\n",
"Datei geschlossen wird.\n",
"\n",
"Durch Überschreiben der Methoden können auch eigene Klassen\n",
"sinnvoll mit einem *Kontextmanager* zusammenarbeiten.\n",
"\n",
"\n"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

+ 9
- 0
09kapitel/091a Textdatei View File

1. Zeile
2. Zeile
3. etwas längere Zeile
4. Zeile - hört das nie auf?
5. Zeile - langsam wird es langweilig
6. Zeile
7. Zeile
8. Zeile
9. letzte Zeile

+ 215
- 0
09kapitel/092 Lesen.ipynb View File

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Software Entwicklung \n",
"\n",
"## Kapitel 9: IO\n",
"\n",
"### 9.4 Dateien lesen\n",
"\n",
"Bei großen Dateien sollte vom vollständigen Einlesen mittels\n",
"<code>read</code> Abstand genommen werden, weil dann\n",
"der gesamte Dateiinhalt im Speicher gehalten werden muss.\n",
"Vielmehr sollte in diesem Fall der Inhalt sukzessive eingelesen\n",
"werden."
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Zu diesem Zweck kann <code>read</code> mit einem Parameter\n",
"aufgerufen werden, der die maximale Anzahl Bytes angibt,\n",
"die gelesen werden sollen."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"091a Textdatei\", \"r\") as f:\n",
" block_size = 10\n",
" block = f.read(block_size)\n",
"\n",
" while len(block)>0:\n",
" print(block, end='*')\n",
" block = f.read(block_size)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Man kann sich das schrittweise Einlesen der Datei mit Hilfe\n",
"eines Schreib-/Lesekopfs vorstellen, der sich\n",
"entlang eines Stroms von Bytes bzw. Zeichen bewegt.\n",
"Jeder Lesevorgang bewegt den Kopf um die Anzahl der\n",
"gelesenen Zeichen vorwärts. Die Position des Kopfs\n",
"innerhalb der Datei kann mittels <code>tell</code>\n",
"ermittelt werden."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"091a Textdatei\", \"r\") as f:\n",
" block_size = 10\n",
" block = f.read(block_size)\n",
"\n",
" while len(block)>0:\n",
" print(block, end='')\n",
" pos = f.tell()\n",
" print(f\"<{pos}>\", end='')\n",
" block = f.read(block_size)"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Die Position des Schreib-/Lesekopfs lässt sich auch\n",
"durch die Methode <code>seek</code> verändern."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"091a Textdatei\", \"r\") as f:\n",
" f.seek(110)\n",
" print(f.read())"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Textdateien sind i.d.R. in Zeilen aufgeteilt, die jeweils\n",
"mit einem Zeilenendezeichen abschließen. Die Methode\n",
"<code>readline</code> liest aus einer Textdatein\n",
"die Daten bis zum nächsten Zeilenende."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"091a Textdatei\", \"r\") as f:\n",
" line = f.readline()\n",
" while len(line)>0:\n",
" print(line, end='')\n",
" line = f.readline()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Diese häufig benötigte Variante des Lesens einer Textdatei\n",
"kann in Python auch mittels einer <code>for</code>-Schleife\n",
"realisiert werden."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"091a Textdatei\", \"r\") as f:\n",
" for line in f:\n",
" print(line, end='')"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

+ 160
- 0
09kapitel/093 Schreiben.ipynb View File

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Software Entwicklung \n",
"\n",
"## Kapitel 9: IO\n",
"\n",
"### 9.4 Dateien schreiben\n",
"\n",
"Voraussetzung dafür, dass in eine Datei geschrieben werden kann,\n",
"ist ein passender Bearbeitungsmodus."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"093a Textdatei\", \"w\") as f:\n",
" f.write(\"Nürnberg ist schön!\")\n",
"\n",
"with open(\"093a Textdatei\", \"r\") as f:\n",
" print(f.read())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Wird der Schreib-/Lesekopf zurückgesetzt, kann der bestehende Inhalt überschrieben werden."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"093a Textdatei\", \"w\") as f:\n",
" f.write(\"Nürnberg ist nice!\")\n",
" pos = f.tell()-5\n",
" f.seek(pos)\n",
" f.write(\"schön!\")\n",
"\n",
"with open(\"093a Textdatei\", \"r\") as f:\n",
" print(f.read())"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Durch den Bearbeitungsmodus <code>'r+'</code> ist es auch\n",
"möglich, mit einem Datei-Objekt zu lesen und zu schreiben."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"093a Textdatei\", \"r+\") as f:\n",
" f.write(\"Nürnberg ist nice!\")\n",
" pos = f.tell()-5\n",
" f.seek(pos)\n",
" f.write(\"schön!\")\n",
" f.seek(0)\n",
" print(f.read())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Anders als bei <code>print</code> wird bei <code>write</code>\n",
"kein Zeilenwechsel angehängt; es muss also ggf. selbst\n",
"hinzugefügt werden."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with open(\"093a Textdatei\", \"r+\") as f:\n",
" f.write(\"Zeile 1\")\n",
" f.write(\"Zeile 2\\n\")\n",
" f.write(\"Zeile 3\\n\")\n",
" f.seek(0)\n",
" print(f.readline())"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

+ 108
- 0
09kapitel/094 Uebung.ipynb View File

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"\n",
"Gegeben ist eine binäre Grafikdatei <code>ohm.png</code>."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"from IPython.display import Image\n",
"Image(filename=\"ohm.png\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"_Aufgabe 1_\n",
"\n",
"Erstellen Sie ein Python-Programm, dass diese Datei in eine zweite\n",
"Datei <code>logo.png</code> kopiert. Übertragen Sie die Daten bitte\n",
"in 32 Byte Paketen."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"from IPython.display import Image\n",
"\n",
"\n",
"with open(\"ohm.png\", \"rb\") as source_file:\n",
" with open(\"logo.png\", \"wb\") as dest_file:\n",
" buffer_size = 32\n",
" buffer = source_file.read(buffer_size)\n",
" while len(buffer)>0:\n",
" dest_file.write(buffer)\n",
" buffer = source_file.read(buffer_size)\n",
"\n",
"\n",
"Image(filename=\"logo.png\")"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

+ 186
- 0
09kapitel/095 Sockets.ipynb View File

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Software Entwicklung \n",
"\n",
"## Kapitel 9: IO\n",
"\n",
"### 9.5 Sockets\n",
"\n",
"So wie der Begriff *Datei* eine griffige Bezeichnung für eine Ansammlung dauerhaft gespeicherter Bytes ist, wird\n",
"mit *Socket* ein Endpunkt für Netzwerkverbindungen bezeichnet.\n",
"Die Kommunikation findet zwischen zwei Sockets *bidirektional* statt, d.h. über jedes Socket können Bytes versendet\n",
"und empfangen werden."
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Sockets stehen in Python durch das Standard-Modul <code>sockets</code> zur Verfügung. Wie schon Dateien belegen auch\n",
"Sockets Betriebssystem-Ressourcen, so dass die Verwendung eines Kontextmanagers ratsam ist."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"import socket\n",
"\n",
"with socket.socket() as s:\n",
" pass"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### 9.5.1 Client-Server-Modell\n",
"\n",
"Zwar sind bei einer bestehenden Kommunikationsverbindung zwischen zwei Sockets die beiden Sockets prinzipiell\n",
"gleichberechtigt, jedoch gibt es Unterschiede beim Kommunikationsaufbau.\n",
"\n",
"* Ein *Server-Socket* verhält sich passiv, d.h. es wartet auf eingehende Verbindungsanfragen. Trifft eine solche\n",
" ein, generiert es ein weiteres Socket, das fest dieser Verbindung zugeordnet wird und über das die\n",
" anschließende Kommunikation abgewickelt wird. Das *Server-Socket* selbst verbleibt im Wartezustand.\n",
"\n",
"* Ein *Client-Socket* übernimmt den aktiven Part. Es kontaktiert das *Server-Socket* und geht selbst die\n",
" Verbindung mit dem daraufhin bereitgestellten Socket ein."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Die Verbindungsaufnahme folgt einem vorgegebenen Ablauf aus definierten Schritten (auch: *Kommunikationsprimitive*).\n",
"\n",
"![Verbindungsaufnahme mit Kommunkationsprimitiven](../img/Primitive.png \"Kommunikationsprimitive\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### 9.5.2 Server-Socket\n",
"\n",
"Ein *Server-Socket* ist eindeutig festgelegt durch das Protokoll (z.B. TCP oder UDP), den Rechner\n",
"(z.B. durch dessen IP-Adresse) und eine Portnummer. Letztere dient dazu, dass mehrere Server-Sockets gleichzeitig\n",
"auf einem Rechner existieren können, ohne sich gegenseitig zu beeinflussen.\n",
"\n",
"So gibt es z.B. auf dem Server <code>medinf.efi.th-nuernberg.de</code> mehrere Server-Sockets,\n",
"die permanent angesprochen werden können:\n",
"\n",
"* Port 22: Nimmt Secure-Shell-Anfragen entgegen\n",
"* Port 80: Nimmt HTTP-Anfragen entgegen\n",
"* Port 443: Nimmt HTTPS-Anfragen entgegen"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Das *Server-Socket* wird mit <code>bind</code> an einen bestimmten Port und eine\n",
"IP-Adresse (ggf. hat ein Rechner mehrere IP-Adressen) gebunden. Das Binden schlägt fehl, wenn die\n",
"Kombination bereits von einem anderen Socket belegt ist.\n",
"\n",
"Anschließend beginnt das *Server-Socket* mit <code>listen</code> zu lauschen. Das Primitiv <code>accept</code>\n",
"blockiert den Server, bis ein *Client-Socket* Verbindung aufnimmt. Damit entsteht ein weiteres Socket mit\n",
"einer vom System vergebenen Portnummer, das dediziert nur für die Verbindung mit diesem Client verwendet wird.\n",
"\n",
"Über dieses neue Socket folgen danach Primitive zum Senden\n",
"<code>send</code> und Empfangen <code>receive</code> von Nachrichten. Anzahl und Abfolge sind\n",
"für Sockets nicht festgelegt, müssen aber zwischen Client und Server abgestimmt sein. So legt z.B.\n",
"das auf Sockets aufsetzende Protokoll HTTP fest, dass zunächst eine Nachricht vom Client\n",
"an den Server (*HTTP-Request*) und anschließend eine Nachricht vom Server an den Client\n",
"(*HTTP-Response*) gesendet wird. Während in der ersten Version von HTTP danach die\n",
"Verbindung wieder abgebaut wurde, ist es aktuellen Versionen möglich, dieses Abfolge\n",
"wiederholt über eine bestehende Verbindung abzuwickeln."
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Eine etablierte Verbindung ist mit <code>close</code> zu schließen. Bei Verwendung eines\n",
"Kontextmanagers erfolgt dies automatisch.\n",
"\n",
"Auch das *Server-Socket* muss geschlossen werden, um das Binden an einen Port zu beenden\n",
"und den Port freizugeben."
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

+ 102
- 0
09kapitel/096 Server.ipynb View File

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Software Entwicklung \n",
"\n",
"## Kapitel 9: IO\n",
"\n",
"### 9.5 Sockets"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### 9.5.3 Beispiel für einen Server"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"import socket\n",
"\n",
"with socket.socket() as server: # Generieren eines Sockets\n",
" host = socket.gethostname() # Die eigene IP-Nummer\n",
" port = 12345 # Festlegen des Ports\n",
" server.bind((host, port)) # Bind\n",
" server.listen() # Listen (blockiert nicht)\n",
" print(\"Ich lausche...\")\n",
"\n",
" for contact in range(0, 10):\n",
" connection, addr = server.accept() # blockiert\n",
" with connection:\n",
" print('Verbindung von ', addr)\n",
" msg = f'Danke für das Vorbeischauen, #{contact+1}!\\n'\n",
" connection.send(msg.encode('utf-8')) # Senden \n",
"\n",
" print(\"Das wars!\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Textnachrichten, die über ein Socket versendet werden sollen, müssen in Bytes\n",
"umgewandelt werden.\n"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

+ 146
- 0
09kapitel/097 Client.ipynb View File

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Software Entwicklung \n",
"\n",
"## Kapitel 9: IO\n",
"\n",
"### 9.5 Sockets\n",
"\n",
"#### 9.5.4 Client-Socket\n",
"\n",
"Da das *Client-Socket* den Server kontaktiert, benötigt es die Adresse und den\n",
"Port des *Server-Sockets*. Mit <code>connect</code>\n",
"wird die Verbindung aufgebaut, sofern an der Gegenstelle ein Server\n",
"im Primitiv <code>accept</code> wartet.\n",
"\n",
"Danach folgen Primitive zum Senden\n",
"<code>send</code> und Empfangen <code>receive</code> von Nachrichten\n",
"in einer mit dem Server abgestimmten Reihenfolge.\n",
"\n",
"Abschließend ist die Verbindung mit <code>close</code> zu schließen. Bei Verwendung eines\n",
"Kontextmanagers erfolgt dies automatisch."
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### 9.5.5 Beispiel für einen Client"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"import socket\n",
"\n",
"with socket.socket() as client: # Generieren des Sockets\n",
" host = socket.gethostname() # Server-IP\n",
" port = 12345 # Server-Port\n",
"\n",
" client.connect((host, port)) # Connect\n",
" bytes = client.recv(1024) # Receive\n",
" print (bytes.decode('utf-8'))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Möchte man ein Socket wie eine Datei behandeln, also statt <code>send</code> und\n",
"<code>recv</code> lieber <code>write</code> und <code>read</code> verwenden, so kann\n",
"mit <code>makefile</code> eine \"Hülle\" um das Socket gelegt werden, die die\n",
"(meisten) Funktionen für Dateien anbietet und übersetzt."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"import socket\n",
"\n",
"with socket.socket() as client: # Generieren des Sockets\n",
" host = socket.gethostname() # Server-IP\n",
" port = 12345 # Server-Port\n",
"\n",
" client.connect((host, port)) # Connect\n",
" with client.makefile(encoding=\"utf-8\") as file:\n",
" text = file.readline()\n",
" print (text)"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Textnachrichten, die über ein Socket empfangen werden, müssen aus den übertragenen Bytes\n",
"abgeleitet werden. Nutzt man die Dateischnittstelle, findet die Konvertierung dort statt.\n",
"\n",
" "
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

BIN
09kapitel/ohm.png View File


+ 22
- 0
09kapitel/rise.css View File

body.rise-enabled div.inner_cell>div.input_area {
font-size: 150%;
}

body.rise-enabled div.output_subarea.output_text.output_result {
font-size: 150%;
}
body.rise-enabled div.output_subarea.output_text.output_stream.output_stdout {
font-size: 150%;
}

body.rise-enabled div.output_subarea.output_html.rendered_html.output_result {
font-size: 150%;
}

body.rise-enabled td {
font-size: 120%;
}

body.rise-enabled th {
font-size: 120%;
}

+ 5
- 0
09kapitel/utf8_text View File

Zeile 1
Zeile 2
Zeile 3
Zeile 4 Hört das denn nie auf?
Zeile 5

Loading…
Cancel
Save