|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- {
- "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
- }
|