9.15. Namen und DNS¶
Jede Seite bisher hat numerische IP-Adressen verwendet – 192.168.1.20 und dergleichen. Echte Anwendungen tun das fast nie. Server heißen example.com oder api.example.com, und die Anwendung schlägt den Namen zur Laufzeit nach, um eine IP zu finden, an die sie Pakete sendet. Dieses Nachschlagen ist das Domain Name System oder DNS.
9.15.1. Worauf ein Name aufgelöst wird¶
Ein Name ist lediglich ein Etikett. example.com trägt selbst keine IP-Information – es muss nachgeschlagen werden, so wie eine Telefonnummer in einem Telefonbuch nachgeschlagen wird. Die DNS-Infrastruktur ist das verteilte Telefonbuch des Internets, und das Ergebnis eines Nachschlagens sind eine oder mehrere IP-Adressen, mit denen sich die Kamera verbinden kann.
example.com -> 93.184.216.34
Ein einzelner Name wird oft auf mehrere Adressen aufgelöst (zur Lastverteilung, geografischen Redundanz, IPv4- und IPv6-Versionen desselben Dienstes). Jede davon funktioniert; die Anwendung wählt eine aus und versucht es damit, wobei sie auf die nächste zurückfällt, falls diese fehlschlägt.
9.15.2. Wie das Nachschlagen abläuft¶
Wenn die Kamera nach example.com fragt:
Die Kamera sendet ein kleines UDP-Datagramm (ja, UDP – siehe UDP – sende ein Paket, hoffe auf das Beste) an ihren konfigurierten DNS-Server. Die Adresse des DNS-Servers stammt aus demselben DHCP-Austausch, der der Kamera ihre eigene IP zugewiesen hat.
Der DNS-Server hat die Antwort möglicherweise bereits zwischengespeichert (er wurde kürzlich gefragt). Ist das der Fall, antwortet er sofort.
Andernfalls durchläuft der DNS-Server die globale DNS-Hierarchie: Er fragt die Root-Server nach
.com, fragt diese Server nachexample.com, fragt jene Server nach dem Namen. Der gesamte Baumdurchlauf bleibt vor der Kamera verborgen; die Kamera sieht eine Anfrage und eine Antwort.Der DNS-Server speichert das Ergebnis für das nächste Mal zwischen und sendet die Antwort als ein weiteres UDP-Datagramm an die Kamera zurück.
Der gesamte Austausch dauert bei einem warmen Cache typischerweise einige Millisekunden, bei einem kalten bis zu etwa hundert.
9.15.3. Die Python-Schnittstelle¶
Die Funktion getaddrinfo() führt das Nachschlagen durch und gibt eine Adresse zurück, die direkt an einen Socket-Konstruktor übergeben werden kann:
import socket
addr = socket.getaddrinfo("example.com", 80)[0][-1]
print(addr)
# ('93.184.216.34', 80)
Die Signatur lautet getaddrinfo(host, port). Der Rückgabewert ist eine Liste von 5-Tupeln (eines pro aufgelöster Adresse); das [0] wählt das erste aus und das [-1] wählt das letzte Feld aus, welches das (ip, port)-Tupel ist, das einem Socket direkt übergeben werden kann:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(socket.getaddrinfo("example.com", 80)[0][-1])
s.send(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
...
Der meiste Kameracode, der mit einem entfernten Server kommuniziert, beginnt mit dieser einen Zeile. Die asyncio-Hilfsfunktionen (asyncio.open_connection()) führen das Nachschlagen intern durch, wenn ein Name statt einer numerischen IP übergeben wird, sodass asynchroner Code getaddrinfo() typischerweise nicht direkt aufruft.
9.15.4. Was schiefgehen kann¶
Kein DNS-Server erreichbar. Wenn WLAN gerade hochgefahren ist und die Verbindung instabil ist, kann der erste
getaddrinfo()-Aufruf einen Timeout erleiden. Es wird einOSErrorausgelöst; wiederholen Sie es, sobald die Verbindung stabil ist.Name existiert nicht. Ein Tippfehler oder ein veralteter Name löst einen
OSErroraus, nachdem der DNS-Server „kein solcher Name“ zurückgegeben hat. Der Fehlercode unterscheidet dies von „DNS-Server nicht erreichbar“, aber für die meisten Kameraanwendungen ist die Wiederholen/Aufgeben-Strategie dieselbe.Zurückgegebene Adresse funktioniert nicht. DNS gibt möglicherweise eine Adresse zurück, die den Dienst nicht mehr hostet. Die Lösung besteht darin, auf den nächsten Eintrag in der Ergebnisliste von
getaddrinfo()zurückzufallen oder den Namen später erneut nachzuschlagen (der DNS-Cache wird sich bis dahin wahrscheinlich aktualisiert haben).Captive Portals. Einige WLAN-Netzwerke fangen DNS ab und geben für alles die IP der Captive-Portal-Seite zurück. Die Kamera scheint sich zu verbinden, aber die zurückerhaltenen Daten stimmen nicht mit dem überein, was der eigentliche Dienst senden würde. In ausgelieferten Umgebungen nicht üblich, aber etwas, das in Konferenz-WLANs und ähnlichen Netzwerken vorkommt.
9.15.5. Der eigene Name der Kamera¶
Die bisherigen Seiten haben die Namen anderer Geräte nachgeschlagen. Die Kamera hat auch einen eigenen Namen, den sie dem lokalen Netzwerk ankündigt, wenn sie nach einer Adresse fragt. Der Standard ist eine generische Kennung, die je nach Board variiert; network.hostname() überschreibt sie mit etwas, das der Rest des Netzwerks erkennt:
import network
network.hostname("kitchen-cam")
# ... then bring the link up as usual ...
Setzen Sie den Hostnamen, bevor Sie die Schnittstelle hochfahren, damit der Name als Teil der anfänglichen Adressanfrage der Kamera hinausgeht und nicht erst danach.
Zwei Dinge geschehen nun, sobald die Kamera dem Netzwerk beigetreten ist. Erstens registrieren die meisten Heimrouter die Hostnamen, denen sie Adressen zuweisen, in ihrem eigenen lokalen Verzeichnis, sodass andere Geräte die Kamera als kitchen-cam erreichen können – ohne die numerische Adresse kennen zu müssen, die der Router zufällig zugewiesen hat. (Unternehmensnetzwerke berücksichtigen dies möglicherweise oder auch nicht; das Verhalten liegt beim Router.) Zweitens betreibt die Kamera selbst ab Werk einen mDNS-Responder, sodass derselbe Name auch als kitchen-cam.local in jedem Netzwerk erreichbar ist, dessen Clients mDNS verstehen – was die meisten modernen Desktop-Betriebssysteme tun.
Bemerkung
Übergeben Sie den reinen Hostnamen an network.hostname() – nur "kitchen-cam", kein .local-Suffix. Die .local-Form ist das, was mDNS zur Nachschlagezeit hinzufügt; sie in den Hostnamen einzubacken lässt die Kamera kitchen-cam.local als einfachen Hostnamen ankündigen, was nicht das ist, was eine der beiden Seiten des Nachschlagens erwartet.
9.15.6. Wenn Namen nicht ausreichen¶
Einige Situationen, bei denen DNS nicht hilft:
Discovery im lokalen Netzwerk. Standard-DNS beantwortet Fragen zu Namen, die im globalen Verzeichnis registriert sind; es weiß nichts über Geräte im lokalen Segment. Multicast DNS (mDNS) ist das System, das diese Lücke füllt. Jedes teilnehmende Gerät tritt einer speziellen Multicast-Gruppe im lokalen Netzwerk bei und lauscht auf Anfragen; wenn ein Gerät nach einem Namen fragt, der auf
.localendet, antwortet dasjenige Gerät direkt, das diesen Namen besitzt. Kein zentraler Server, keine DNS-Konfiguration. Bonjour auf Apple-Geräten, Avahi auf Linux und Windows 10+ sprechen alle dasselbe Protokoll – weshalb der Namekitchen-cam.local, den der vorige Abschnitt eingerichtet hat, in einem Heimnetzwerk ohne weitere Konfiguration aufgelöst wird.Die Seite der Kamera bei diesem Austausch ist der Responder, und er läuft bereits. Was der Kamera fehlt, ist ein Resolver – die andere Hälfte, die es einem Skript erlauben würde, das Netzwerk zu fragen „Wo ist
printer.local?“ und eine Antwort zurückzubekommen. Der mitgelieferte mDNS-Code ist reiner Responder (eingebettete Geräte sind typischerweise das gefundene Ding, nicht das findende). Wenn Discovery in die andere Richtung fließen muss, ist UDP-Broadcast (siehe UDP – sende ein Paket, hoffe auf das Beste) die einfachere Antwort für den Fall des lokalen Segments, oder ein reines Python-Modul wie cbrand/micropython-mdns fügt einen vollständigen Resolver hinzu.IPv6-Namen.
getaddrinfo()gibt sowohl IPv4- als auch IPv6-Ergebnisse zurück, wenn beide verfügbar sind. Wählen Sie die Familie, die der Socket der Anwendung verwenden kann.
Für den meisten kameraseitigen Code ist getaddrinfo ein Einzeiler am Anfang jeder Funktion, die eine Netzwerkverbindung öffnet. Die Beispiele andernorts in diesem Abschnitt, die gegen "192.168.1.20" liefen, würden auf dieselbe Weise gegen einen öffentlichen Namen wie "api.example.com" funktionieren – man muss nur zuerst auflösen.