9.15. Nevek és DNS¶
Az eddigi minden oldal numerikus IP-címeket használt – 192.168.1.20 és hasonlókat. A valódi alkalmazások szinte soha nem ezt teszik. A szervereknek example.com vagy api.example.com nevük van, és az alkalmazás futási időben keresi ki a nevet, hogy megtalálja az IP-t, amelyre csomagokat küldjön. Ez a keresés a Domain Name System, azaz a DNS.
9.15.1. Mire oldódik fel egy név¶
A név csak egy címke. Az example.com önmagában nem hordoz semmilyen IP-információt – ki kell keresni, ugyanúgy, ahogy egy telefonszámot keresünk ki egy telefonkönyvben. A DNS-infrastruktúra az internet elosztott telefonkönyve, és a keresés eredménye egy vagy több IP-cím, amelyhez a kamera csatlakozni tud.
example.com -> 93.184.216.34
Egy név gyakran több címre is feloldódik (terheléselosztás, földrajzi redundancia, ugyanazon szolgáltatás IPv4 és IPv6 verziói miatt). Bármelyik működik; az alkalmazás kiválaszt egyet és megpróbálja, és ha az nem sikerül, a következőre vált.
9.15.2. Hogyan történik a keresés¶
Amikor a kamera az example.com címet kéri:
A kamera egy kis UDP-datagramot küld (igen, UDP – lásd: UDP – küldj egy csomagot, remélj a legjobbat) a beállított DNS-szerveréhez. A DNS-szerver címe ugyanabból a DHCP-cseréből származik, amely a kamerának a saját IP-jét adta.
Lehet, hogy a DNS-szervernek már gyorsítótárazva van a válasz (mert nemrég kérdezték meg). Ha igen, azonnal válaszol.
Ha nem, a DNS-szerver bejárja a globális DNS-hierarchiát: megkérdezi a root szervereket a
.comfelől, megkérdezi azokat a szervereket azexample.comfelől, majd megkérdezi azokat a szervereket a név felől. Az egész faljárás rejtve marad a kamera elől; a kamera egyetlen lekérdezést és egyetlen választ lát.A DNS-szerver gyorsítótárazza az eredményt a következő alkalomra, és egy újabb UDP-datagramként visszaküldi a választ a kamerának.
Az egész csere általában néhány ezredmásodpercet vesz igénybe meleg gyorsítótár esetén, és akár száz körülit hideg gyorsítótár esetén.
9.15.3. A Python-interfész¶
A getaddrinfo() függvény elvégzi a keresést, és egy olyan címet ad vissza, amely készen áll egy socket-konstruktornak való átadásra:
import socket
addr = socket.getaddrinfo("example.com", 80)[0][-1]
print(addr)
# ('93.184.216.34', 80)
A szignatúra getaddrinfo(host, port). A visszatérési érték 5-ös tuple-ök listája (egy minden feloldott címhez); a [0] az elsőt választja ki, a [-1] pedig az utolsó mezőt, amely az (ip, port) tuple, ami közvetlenül átadható egy socketnek:
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")
...
A legtöbb kameraprogram, amely egy távoli szerverrel kommunikál, ezzel az egy sorral kezdődik. Az asyncio segédfüggvények (asyncio.open_connection()) belül elvégzik a keresést, ha numerikus IP helyett nevet adsz át, így az aszinkron kód jellemzően nem hívja meg közvetlenül a getaddrinfo() függvényt.
9.15.4. Mi mehet rosszul¶
Nincs elérhető DNS-szerver. Ha a Wi-Fi épp most jött fel, és a kapcsolat ingatag, az első
getaddrinfo()hívás időtúllépéssel végződhet.OSErrorkeletkezik; próbáld újra, amint a kapcsolat stabil.A név nem létezik. Egy elgépelés vagy egy elavult név
OSError-t vált ki, miután a DNS-szerver visszaadja a „nincs ilyen név” választ. A hibakód megkülönbözteti ezt a „DNS-szerver nem elérhető” hibától, de a legtöbb kameraalkalmazás esetében az újrapróbálkozási/feladási politika ugyanaz.A visszaadott cím nem működik. A DNS visszaadhat olyan címet, amely már nem hosztolja a szolgáltatást. A megoldás az, hogy a
getaddrinfo()eredménylistájának következő bejegyzésére váltasz, vagy később újra kikeresed a nevet (a DNS gyorsítótár addigra valószínűleg frissült).Captive portálok. Egyes Wi-Fi-hálózatok lekapják a DNS-t, és minden kérésre a captive portál oldalának IP-jét adják vissza. Úgy fog tűnni, mintha a kamera csatlakozna, de a visszakapott adatok nem fognak egyezni azzal, amit a tényleges szolgáltatás küldene. Üzemi környezetben nem gyakori, de olyasmi, ami konferenciás Wi-Fin és hasonló hálózatokon megtörténik.
9.15.5. A kamera saját neve¶
Az eddigi oldalak más eszközök neveit keresték ki. A kamerának is van saját neve, amelyet hirdet a helyi hálózat felé, amikor címet kér. Az alapértelmezett egy általános azonosító, amely panelenként változik; a network.hostname() valami olyasmivel írja felül, amit a hálózat többi része felismer:
import network
network.hostname("kitchen-cam")
# ... then bring the link up as usual ...
Állítsd be a hostnevet azelőtt, hogy az interfészt felhoznád, hogy a név a kamera kezdeti címkérésének részeként menjen ki, ne pedig utána.
Két dolog történik most, miután a kamera csatlakozott a hálózathoz. Először is, a legtöbb otthoni router regisztrálja a saját helyi keresőjébe azokat a hostneveket, amelyeknek címet ad, így más eszközök elérhetik a kamerát kitchen-cam néven – anélkül, hogy ismerniük kellene a numerikus címet, amelyet a router éppen kiosztott. (Vállalati hálózatok ezt tiszteletben tarthatják vagy sem; a viselkedés a routeron múlik.) Másodszor, a kamera maga egy mDNS-válaszolót futtat alapból, így ugyanaz a név kitchen-cam.local néven is elérhető bármely olyan hálózaton, amelynek kliensei megértik az mDNS-t – amit a legtöbb modern asztali operációs rendszer megtesz.
Megjegyzés
A puszta hostnevet add át a network.hostname() függvénynek – csak a "kitchen-cam" nevet, .local utótag nélkül. A .local formát az mDNS adja hozzá kereséskor; ha beleépíted a hostnévbe, akkor a kamera a kitchen-cam.local nevet sima hostnévként hirdeti, ami nem az, amit a keresés egyik fele sem vár.
9.15.6. Amikor a nevek nem elegendők¶
Néhány helyzet, amelyben a DNS nem segít:
Felfedezés a helyi hálózaton. A szabványos DNS a globális névtárba regisztrált nevekkel kapcsolatos kérdésekre válaszol; semmit nem tud a helyi szegmensen lévő eszközökről. A Multicast DNS (mDNS) az a rendszer, amely betölti ezt a rést. Minden részt vevő eszköz csatlakozik egy speciális multicast-csoporthoz a helyi hálózaton, és figyeli a lekérdezéseket; amikor egy eszköz egy
.localvégződésű nevet kér, az az eszköz válaszol közvetlenül, amelyik birtokolja azt a nevet. Nincs központi szerver, nincs DNS-konfiguráció. Az Apple-eszközökön a Bonjour, a Linuxon az Avahi és a Windows 10+ mind ugyanazt a protokollt beszéli – ezért oldódik fel az előző szakaszban beállítottkitchen-cam.localnév egy otthoni hálózaton minden további konfiguráció nélkül.A kamera oldala ennek a cserének a válaszoló (responder), és az már fut. Amivel a kamera nem rendelkezik, az egy feloldó (resolver) – a másik fél, amely lehetővé tenné, hogy egy szkript megkérdezze a hálózatot, „hol van a
printer.local?”, és választ kapjon rá. A mellékelt mDNS-kód csak válaszoló (a beágyazott eszközök jellemzően a megtalálandó dolgok, nem pedig a keresést végzők). Amikor a felfedezésnek a másik irányba kell folynia, a UDP-broadcast (lásd: UDP – küldj egy csomagot, remélj a legjobbat) az egyszerűbb megoldás a helyi szegmens esetében, vagy egy tiszta Python modul, mint a cbrand/micropython-mdns, ad hozzá teljes feloldót.IPv6-nevek. A
getaddrinfo()mind IPv4, mind IPv6 eredményeket visszaad, ha mindkettő elérhető. Válaszd ki azt a családot, amelyet az alkalmazás socketje használni tud.
A legtöbb kameraoldali kódhoz a getaddrinfo egy egysoros az olyan függvények tetején, amelyek hálózati kapcsolatot nyitnak. Az ebben a szakaszban máshol szereplő példák, amelyek a "192.168.1.20" címmel futottak, mind ugyanígy működnének egy nyilvános névvel, mint a "api.example.com" – csak előbb fel kell oldani.