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