9.15. Adlar ve DNS¶
Şimdiye kadarki her sayfa sayısal IP adresleri kullandı – 192.168.1.20 ve benzeri. Gerçek uygulamalar bunu neredeyse hiç yapmaz. Sunucular example.com veya api.example.com olarak adlandırılır ve uygulama, paket göndereceği bir IP bulmak için adı çalışma zamanında arar. Bu arama, Etki Alanı Adı Sistemi (Domain Name System) yani DNS’tir.
9.15.1. Bir adın neye çözümlendiği¶
Bir ad yalnızca bir etikettir. example.com kendisi hiçbir IP bilgisi taşımaz – bir telefon numarasının telefon rehberinde aranması gibi, aranması gerekir. DNS altyapısı internetin dağıtık telefon rehberidir ve bir aramanın sonucu, kameranın bağlanabileceği bir veya daha fazla IP adresidir.
example.com -> 93.184.216.34
Tek bir ad genellikle birden fazla adrese çözümlenir (yük dengeleme, coğrafi yedeklilik, aynı hizmetin IPv4 ve IPv6 sürümleri için). Bunlardan herhangi biri işe yarar; uygulama birini seçer ve dener, başarısız olursa bir sonrakine geçer.
9.15.2. Aramanın nasıl gerçekleştiği¶
Kamera example.com adını sorduğunda:
Kamera, yapılandırılmış DNS sunucusuna küçük bir UDP datagramı gönderir (evet, UDP – bkz. UDP – bir paket gönder, en iyisini um). DNS sunucusunun adresi, kameraya kendi IP’sini veren aynı DHCP alışverişinden gelmiştir.
DNS sunucusu yanıtı zaten önbelleğe almış olabilir (yakın zamanda sorulmuştur). Eğer öyleyse hemen yanıt verir.
Değilse, DNS sunucusu küresel DNS hiyerarşisinde gezinir: kök (root) sunuculara
.comhakkında sorar, o sunucularaexample.comhakkında sorar, o sunuculara da adın kendisi hakkında sorar. Tüm bu ağaç gezintisi kameradan gizlenir; kamera bir sorgu ve bir yanıt görür.DNS sunucusu sonucu bir sonraki sefer için önbelleğe alır ve yanıtı başka bir UDP datagramı olarak kameraya geri gönderir.
Tüm alışveriş, sıcak bir önbellekte tipik olarak birkaç milisaniye, soğuk bir önbellekte ise yüz milisaniyeye kadar sürer.
9.15.3. Python arayüzü¶
getaddrinfo() işlevi aramayı yapar ve bir soket yapıcısına vermeye hazır bir adres döndürür:
import socket
addr = socket.getaddrinfo("example.com", 80)[0][-1]
print(addr)
# ('93.184.216.34', 80)
İmza getaddrinfo(host, port) şeklindedir. Dönüş değeri 5’li demetlerden oluşan bir listedir (çözümlenen her adres için biri); [0] ilkini seçer ve [-1] son alanı seçer, yani bir sokete doğrudan verilebilecek (ip, port) demetini:
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")
...
Uzak bir sunucuyla konuşan çoğu kamera kodu bu tek satırla başlar. asyncio yardımcıları (asyncio.open_connection()), sayısal bir IP yerine bir ad geçilirse aramayı dahili olarak yapar, bu nedenle asenkron kod tipik olarak getaddrinfo() işlevini doğrudan çağırmaz.
9.15.4. Neler ters gidebilir¶
Ulaşılabilir DNS sunucusu yok. Wi-Fi yeni geldiyse ve bağlantı kararsızsa, ilk
getaddrinfo()çağrısı zaman aşımına uğrayabilir.OSErrorfırlatılır; bağlantı kararlı olduğunda yeniden deneyin.Ad mevcut değil. Bir yazım hatası veya eski bir ad, DNS sunucusu “böyle bir ad yok” döndürdükten sonra
OSErrorfırlatır. Hata kodu bunu “DNS sunucusuna ulaşılamıyor” durumundan ayırır, ancak çoğu kamera uygulaması için yeniden deneme/vazgeçme politikası aynıdır.Döndürülen adres çalışmıyor. DNS, artık hizmeti barındırmayan bir adres döndürebilir. Çözüm,
getaddrinfo()sonuç listesindeki bir sonraki girişe geçmek veya adı daha sonra tekrar aramaktır (DNS önbelleği o zamana kadar muhtemelen güncellenmiş olacaktır).Captive portal’lar. Bazı Wi-Fi ağları DNS’i ele geçirir ve her şey için captive-portal sayfasının IP’sini döndürür. Kamera bağlanmış gibi görünür, ancak geri aldığı veriler gerçek hizmetin göndereceğiyle eşleşmez. Dağıtılmış ortamlarda yaygın değildir, ancak konferans Wi-Fi’sinde ve benzer ağlarda olan bir şeydir.
9.15.5. Kameranın kendi adı¶
Şimdiye kadarki sayfalar diğer cihazların adlarını aradı. Kameranın da bir adres istediğinde yerel ağa duyurduğu kendi adı vardır. Varsayılan, karttan karta değişen genel bir tanımlayıcıdır; network.hostname(), bunu ağın geri kalanının tanıyacağı bir şeyle geçersiz kılar:
import network
network.hostname("kitchen-cam")
# ... then bring the link up as usual ...
Ana bilgisayar adını arayüzü açmadan önce ayarlayın, böylece ad kameranın ilk adres isteğinin bir parçası olarak gönderilir, sonradan değil.
Kamera ağa katıldıktan sonra artık iki şey olur. İlk olarak, çoğu ev yönlendiricisi adres verdiği ana bilgisayar adlarını kendi yerel aramalarına kaydeder, böylece diğer cihazlar kameraya yönlendiricinin atadığı sayısal adresi bilmek zorunda kalmadan kitchen-cam olarak ulaşabilir. (Kurumsal ağlar bunu dikkate alabilir veya almayabilir; davranış yönlendiriciye bağlıdır.) İkincisi, kamera kendisi kutudan çıkar çıkmaz bir mDNS yanıtlayıcısı çalıştırır, böylece aynı ad, istemcileri mDNS’i anlayan herhangi bir ağda – ki çoğu modern masaüstü işletim sistemi anlar – kitchen-cam.local olarak da ulaşılabilir.
Not
Çıplak ana bilgisayar adını network.hostname() işlevine geçirin – yalnızca "kitchen-cam", .local son eki olmadan. .local biçimi, mDNS’in arama sırasında eklediği şeydir; bunu ana bilgisayar adına yerleştirmek, kameranın kitchen-cam.local adresini düz bir ana bilgisayar adı olarak duyurmasına neden olur ki bu aramanın hiçbir tarafının beklediği şey değildir.
9.15.6. Adlar yeterli olmadığında¶
DNS’in yardımcı olmadığı birkaç durum vardır:
Yerel ağda keşif. Standart DNS, küresel dizine kayıtlı adlar hakkındaki soruları yanıtlar; yerel segmentteki cihazlar hakkında hiçbir şey bilmez. Bu boşluğu dolduran sistem Multicast DNS (mDNS) sistemidir. Katılan her cihaz yerel ağda özel bir çok noktaya yayın (multicast) grubuna katılır ve sorguları dinler; bir cihaz
.localile biten bir ad sorduğunda, o ada sahip olan cihaz doğrudan yanıt verir. Merkezi sunucu yok, DNS yapılandırması yok. Apple cihazlarında Bonjour, Linux’ta Avahi ve Windows 10+ aynı protokolü konuşur – bu yüzden önceki bölümün kurduğukitchen-cam.localadı, ek hiçbir şey yapılandırılmadan bir ev ağında çözümlenir.Bu alışverişin kamera tarafı yanıtlayıcı (responder)‘dır ve zaten çalışmaktadır. Kamerada olmayan şey bir çözümleyici (resolver)‘dir – diğer yarısı, yani bir betiğin ağa “
printer.localnerede?” diye sormasına ve bir yanıt almasına izin verecek olan kısım. Paketlenmiş mDNS kodu yalnızca yanıtlayıcıdır (gömülü cihazlar tipik olarak bulunan şeydir, bulan şey değil). Keşfin diğer yöne akması gerektiğinde, UDP yayını (bkz. UDP – bir paket gönder, en iyisini um) yerel segment durumu için daha basit bir yanıttır veya cbrand/micropython-mdns gibi saf Python bir modül tam bir çözümleyici ekler.IPv6 adları.
getaddrinfo(), her ikisi de mevcutsa hem IPv4 hem de IPv6 sonuçları döndürür. Uygulamanın soketinin kullanabileceği aileyi seçin.
Çoğu kamera tarafı kod için getaddrinfo, bir ağ bağlantısı açan herhangi bir işlevin başında tek satırlık bir ifadedir. Bu bölümün başka yerlerinde "192.168.1.20" adresine karşı çalışan örnekler, "api.example.com" gibi bir genel ada karşı da aynı şekilde çalışırdı – yalnızca önce çözümleyin.