Ders 11 / 14
Ağ İstemcisi
Ağ istemcisi bir isteği tanımlar, ara katmanlardan geçirir ve gelen yanıtı dizileştirmeyle çözer; çözülen alanlar okumanın ağ basamağını kurar. Ders çözülmüş yanıtın okumasının kökenini, önbelleğe alınmış yanıtın ve çözülemeyen alanın neye düştüğünü ölçer.
Yayın Güncelleme
Bu derste
- İstek tanımı, ara katman ve dizileştirmenin ağ istemcisindeki görevlerini ayırır
- Çözülen yanıtın alanlarının okumanın ağ basamağını kurduğunu açıklar
- Çözülmüş bir yanıtın okumasının kökenini ağ olarak ölçer
- Önbelleğe alınmış yanıtın diskten geldiğini, çözülemeyen alanın varsayılana düştüğünü gösterir
İçindekiler
Önceki derste dosya aynı aygıtın diskindeydi. Verinin çoğu ise başka bir makinededir ve ona bir istekle ulaşılır. Bu derste o isteğin yanıtının zincire nasıl girdiğine bakıyoruz: yanıt bir metin olarak gelir, çözülür ve ancak çözüldüğü kadarıyla okuma için bir yanıt olur. Dersin sorusu önceki derslerle aynıdır: bu okumanın yanıtı nereden geliyor?
// Origin.kt — bir okumanin yanitinin hangi basamaktan geldigini siniflandirir
class Tier(val origin: String, private val entries: Map<String, String>) {
init {
require(origin in listOf("bellek", "disk", "ag")) { "gecersiz basamak: $origin" }
}
fun lookup(key: String): String? = entries[key]
}
class Read(val label: String, val key: String, chain: List<Tier>, fallback: String) {
private val hit: Tier? = chain.firstOrNull { it.lookup(key) != null }
val value: String = hit?.lookup(key) ?: fallback
val origin: String = hit?.origin ?: "varsayilan"
fun show() {
println("$label: anahtar=$key | deger=$value -> $origin")
}
}
fun countOrigins(reads: List<Read>) {
for (name in listOf("bellek", "disk", "ag", "varsayilan")) {
println("$name: ${reads.count { it.origin == name }}")
}
}
İstek, Ara Katman, Dizileştirme
Ağ istemcisi (network client) üç iş yapar. İstek tanımı, hangi adrese hangi parametrelerle gidileceğini bir arayüz olarak yazar. Ara katman (interceptor), isteğin ve yanıtın arasına girip başlık eklemek, günlüğe yazmak ya da yanıtı saklamak gibi işleri yapar. Dizileştirme (serialization), yanıt gövdesindeki metni uygulamanın sınıflarına çevirir.
// Platform kodu: ProductApi
interface ProductApi {
@GET("urun")
suspend fun product(@Query("id") id: String, @Query("dil") lang: String): ProductDto
}
@Serializable
data class ProductDto(
val fiyat: String,
val stok: Int = 0,
val kampanya: String? = null,
)
İstek tanımı arayüzde yazılıdır; @GET adresi, @Query parametreleri verir. Yanıt gövdesi ProductDto’ya çözülür ve gövdede olmayan alan, sınıftaki varsayılan değere düşer. Ara katman da ayrı bir sınıftır.
// Platform kodu: CacheHeaderInterceptor
class CacheHeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
return response.newBuilder()
.header("Cache-Control", "max-age=60")
.build()
}
}
Bu iki parça platform kodudur ve burada çıktı, süre ya da yanıt kodu iddia etmiyoruz. Model, platformun bu kurallarını kurar; model platformun kendisi değildir.
Modelde istek, bir adres ve parametrelerden kurulan tek bir satırdır. Yanıt ise anahtar=değer çiftlerinin noktalı virgülle ayrıldığı bir gövdedir; çözücü bu gövdeden bir eşlem çıkarır. = işareti taşımayan parça çözülemez ve eşleme girmez.
// Wire.kt — istegi tek satira kurar, yanit govdesini esleme cozer
fun requestLine(path: String, query: Map<String, String>): String =
"GET $path?" + query.toSortedMap().entries.joinToString("&") { "${it.key}=${it.value}" }
fun decodeResponse(body: String): Map<String, String> =
body.split(";")
.filter { "=" in it }
.associate { part -> part.substringBefore("=") to part.substringAfter("=") }
Ekran üç değer okur. Her birinin yedek değeri vardır.
// Product.kt — urun ekraninin okudugu uc deger
fun readProduct(chain: List<Tier>): List<Read> = listOf(
Read("fiyat", "urun.fiyat", chain, "bilinmiyor"),
Read("stok", "urun.stok", chain, "0"),
Read("kampanya", "kampanya.kod", chain, "yok"),
)
Çözülen Yanıt Ağdır
Sunucu üç alanlı bir gövde döndürür. Çözücü gövdeyi eşleme çevirir ve bu eşlem ağ basamağıdır.
// Main.kt — cozulen yanit agin eslemini kurar
fun main() {
println(requestLine("/urun", mapOf("id" to "7", "dil" to "tr")))
val body = "urun.fiyat=125;urun.stok=8;kampanya.kod=YAZ10"
val network = Tier("ag", decodeResponse(body))
val reads = readProduct(listOf(network))
reads.forEach { it.show() }
countOrigins(reads)
}
GET /urun?dil=tr&id=7 fiyat: anahtar=urun.fiyat | deger=125 -> ag stok: anahtar=urun.stok | deger=8 -> ag kampanya: anahtar=kampanya.kod | deger=YAZ10 -> ag bellek: 0 disk: 0 ag: 3 varsayilan: 0
Üç alanın üçü de ağdan geldi. Bu dersin kökeni ağdır: çözülen yanıtın alanları ağ basamağını kurar. Ağ basamağı, istek gidip yanıt çözüldükten sonra oluşan bir eşlemdir; çözülmemiş bir metin okumaya yanıt veremez.
VK1. Model, isteğin her zaman başarılı olduğunu ve yanıt gövdesinin tamamının geldiğini varsayar. Platformda bağlantının kopması, zaman aşımı ve sunucunun hata kodu dönmesi modelde yoktur; modelde ağ basamağı ya bir eşlemdir ya hiç kurulmaz.
Sınırlayıcı Ölçüm
İki şey ağ kökenini bozar. İlki ara katmanın yanıtı saklamasıdır: önceki isteğin yanıtı diskteki bir önbellekte kalmışsa, sonraki okuma o önbelleğe bakar. İkincisi çözülemeyen alandır: gövdede olan ama çözücünün eşleme alamadığı bir parça okumaya yanıt vermez.
Önce önbellek. Önbellek, bir önceki isteğin gövdesinden çözülmüş bir disk basamağıdır ve zincirde ağdan önce gelir. Önbellekteki gövde eskidir: fiyat 120, kampanya yok.
// Main.kt — onbellege alinmis yanit diskten, onbellekte olmayan alan agdan gelir
fun main() {
val cachedBody = "urun.fiyat=120;urun.stok=8"
val freshBody = "urun.fiyat=125;urun.stok=8;kampanya.kod=YAZ10"
val cache = Tier("disk", decodeResponse(cachedBody))
val network = Tier("ag", decodeResponse(freshBody))
val reads = readProduct(listOf(cache, network))
reads.forEach { it.show() }
countOrigins(reads)
}
fiyat: anahtar=urun.fiyat | deger=120 -> disk stok: anahtar=urun.stok | deger=8 -> disk kampanya: anahtar=kampanya.kod | deger=YAZ10 -> ag bellek: 0 disk: 2 ag: 1 varsayilan: 0
Fiyat ve stok önbellekten, yani diskten okundu. Fiyat 120’dir; sunucudaki güncel değer 125 olsa da okuma ona ulaşmadı. Kampanya önbellekte yoktu ve ağdan geldi. Kural sırayı görür, tazeliği görmez.
Şimdi çözülemeyen alan. Gövdede urun.stok parçası var, ama = işareti ve değeri yok.
// Main.kt — cozulemeyen alan agin eslemine girmez ve varsayilana duser
fun main() {
val body = "urun.fiyat=125;urun.stok;kampanya.kod=YAZ10"
val network = Tier("ag", decodeResponse(body))
val reads = readProduct(listOf(network))
reads.forEach { it.show() }
countOrigins(reads)
}
fiyat: anahtar=urun.fiyat | deger=125 -> ag stok: anahtar=urun.stok | deger=0 -> varsayilan kampanya: anahtar=kampanya.kod | deger=YAZ10 -> ag bellek: 0 disk: 0 ag: 2 varsayilan: 1
Sunucu stok alanını gönderdi, ama çözücü onu eşleme alamadı. Okuma için o alan yok sayılır ve yanıt yedek değer olan 0’dır. Platformda dizileştirmedeki varsayılan değer kuralı bunun yalnız bir yarısını karşılar: alan gövdede yoksa sınıftaki varsayılan değer kullanılır. Gövdede olup çözülemeyen değer ise varsayılan ayarda hata verir; varsayılana düşmesi için ayrıca açılan bir ayar gerekir.
Ölçümün söylemediği şey, gövdenin neden bozuk olduğudur ve 0’ın stok için doğru bir değer olup olmadığıdır. Kural yalnız yanıtın hangi basamaktan geldiğini söyler.
VK2. Model, çözücüyü yalnız anahtar=değer biçimi için kurar. Platformda iç içe nesneler, listeler, tür uyuşmazlığı ve bilinmeyen alanların yok sayılması modelde yoktur.
Özet
- Bu dersin kökeni: ağ. Çözülen yanıtın alanları ağ basamağını kurar ve okuma o basamaktan yanıtlanır.
- Ağ istemcisi isteği tanımlar, ara katmanlardan geçirir ve yanıtı dizileştirmeyle çözer.
- Üç alanlı bir yanıt çözülünce üç okumanın üçü ağdır: ağ 3.
- Önbelleğe alınmış yanıt zincirde ağdan önce gelirse okuma diskten yanıtlanır: disk 2, ağ 1. Fiyat 120 kalır, sunucudaki 125’i kural görmez.
- Çözülemeyen alan ağ eşlemine girmez; o okuma varsayılana düşer: ağ 2, varsayılan 1.
Sonraki Adım
Bu derste önbellek, eski bir yanıtın çözülmüş hâli olarak yalnız bir basamaktı. Yanıtı kalıcı olarak diske yazıp ekranın yalnız diski okumasını sağlamak ayrı bir tasarımdır: çevrimdışı çalışmanın temeli. Sıradaki ders, Önbellekleme ve Çevrimdışı Destek, ağdan diske yazan bir yenilemenin okumayı hangi kökene getirdiğini ve ağ düşünce kökenin neden aynı kalıp değerin eskidiğini ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.