Ders 03 / 16
Başlıklar ve İçerik Pazarlığı
Alan eklemek karar kazandırmaz: üç yeni başlık baytı yüzde 84 artırıp sıfır karar getirirken, pazarlığa giren alanın bildirilmesi dokuz yanlış kopyayı düzeltir.
İçindekiler
Önceki ders yanıtın ilk satırını ölçtü ve bir şeyi söylemeden bıraktı: durum satırı yanıtın ne olduğunu söyler, hangi karşılığının gönderildiğini söylemez. Aynı ölçüm kaydı ayrı biçimlerde, ayrı dillerde, ayrı sıkıştırmalarla sunulabilir ve hepsi 200 ile döner.
Bu seçimin yapıldığı yer başlık alanlarıdır. Bu ders iki soruyu birden sorar. Birincisi: iletiye alan eklemek aracıya karar kazandırır mı. İkincisi: aynı adresin birden çok karşılığı varken, seçimin hangi alana bakılarak yapıldığı bildirilmezse aracı hangi kopyayı kime verir.
İki Tür Başlık Alanı
Başlık alanı, iki nokta ile ayrılmış bir ad ve bir değerdir. Aşağıdaki döküm öğretim amaçlıdır ve çalıştırılmaz:
GET /olcum/kuzey HTTP/1.1 Host: istasyon.ornek Accept: application/json Accept-Language: tr X-Izleme-Kimligi: iz-0004
Aracı bakımından bu beş satır iki kümeye ayrılır. Host aracının yönlendirme kararını
kurar; Accept ailesi sunucunun hangi karşılığı üreteceğini belirler. Son satır ise
aracının çözemediği bir alandır: adını okur, değerini okur, ama ondan hiçbir karar
çıkaramaz.
Bu ayrım kursun ölçüsünün doğrudan karşılığıdır. Aracının çözemediği alan, aracı için bayttan başka bir şey değildir. Bu cümle bir sezgidir; bu dersin ilk ölçümü onu sayıya çevirir.
Gösterim ve Pazarlık
Bir adres bir kaynağı adlandırır; kaynağın ağ üzerinde taşınan karşılığına gösterim (representation) denir. Aynı kaynağın birden çok gösterimi olabilir: aynı ölçüm kaydı yapılandırılmış bir biçimde de, virgülle ayrılmış satırlar hâlinde de, düz metin olarak da verilebilir.
İstemci hangisini istediğini Accept ailesindeki alanlarla bildirir; sunucu bu bildirime
bakarak bir gösterim seçer. Bu seçime içerik pazarlığı (content negotiation) denir. Üç
ekseni vardır ve üçü de aynı düzeneği kullanır:
| Eksen | İstemcinin bildirimi | Seçilen |
|---|---|---|
| Biçim | Accept |
Ortam türü (media type) |
| Dil | Accept-Language |
Metnin dili |
| Kodlama | Accept-Encoding |
Aktarımdaki sıkıştırma |
Pazarlığın aracı için doğurduğu sonuç şudur: tek bir adres artık tek bir yanıta karşılık gelmez. Aracı bir kopyayı sakladığında, o kopyanın hangi istek için üretildiğini de bilmek zorundadır. Bilmezse, sakladığı kopyayı yanlış istemciye verir.
İsteyenin Bildirimi, Verenin Bildirimi
Pazarlık iki bildirimle yürür ve ikisi ayrı yönlerdedir. İstek tarafındaki Accept ailesi
istemcinin kabul edebileceklerini sayar; bir tercih listesidir, tek bir seçim değildir.
Yanıt tarafındaki Content-Type ise sunucunun gerçekten gönderdiğini bildirir ve
tektir.
Aracının ikisine de ihtiyacı vardır, ayrı nedenlerle. İstek tarafındaki bildirim, elindeki kopyanın bu isteğe uyup uymadığını sınamasını sağlar. Yanıt tarafındaki bildirim, sakladığı kopyanın ne olduğunu bilmesini sağlar. Biri olmadan öbürü işe yaramaz: istemcinin ne istediğini bilmek, elde ne olduğu bilinmeden bir eşleşme kurmaz.
İkisinin yanılma biçimi de ayrıdır. Accept bir tercih listesi olduğu için sunucu
listedeki hiçbir seçeneği üretemeyebilir; o durumda pazarlık sonuçsuz kalır ve karar
istemciye döner. Content-Type ise tek bir değer olduğu için yanlış yazılabilir: sunucu bir
biçim gönderip başka bir biçim bildirdiğinde aracı yanlış bildirime göre saklar ve kopyayı
yanlış anahtara bağlar.
Kodlama ekseni bu ikisinden bir noktada ayrılır. Biçim ve dil, gösterimin anlamına dokunur: başka biçim başka bir kayıt düzeni, başka dil başka bir metindir. Kodlama ise anlamı değiştirmez, yalnız aktarımdaki temsili değiştirir — sıkıştırılmış kayıt açıldığında sıkıştırılmamışıyla aynıdır. Aracı bakımından fark yine de yok sayılamaz: sıkıştırılmış bir kopyayı, sıkıştırmayı kabul ettiğini bildirmemiş bir istemciye vermek o istemci için okunamayan bir yanıt üretir. Anlam aynı kalsa da anahtar ayrı tutulmak zorundadır.
İki ölçümün varsayımları:
- HA13 — Aynı kırk alışveriş ve aynı beş karar kullanılır; üzerine ayrı bir üreteçle her
alışverişin istediği biçim ve dil atanır.
kahinvearaciişlevlerine dokunulmaz. - HA14 — Eklenen üç alan gerçek bilgi taşır ama aracının kodunda hiçbir dala girmez; ölçülen şey alanın büyüklüğü değil, okuyanın onunla bir dal kurup kuramadığıdır.
- HA15 — İkinci ölçüm yalnız saklanabilir alışverişler üzerinde yürür: güvenli yöntemli ve kişiye özel olmayanlar. Kırk alışverişin geri kalanı aracının deposuna girmez.
- HA16 — Aracı anahtar başına tek bir kopya saklar ve anahtara adresin yanında yalnız bildirilen alanlar girer; ilk gelen kopya yerini tutar ve sonraki isteklere o verilir.
- HA17 — İstemcinin istediği gösterim bilinir çünkü onu da biz ürettik; kopyanın doğru mu yanlış mı verildiği bu bilinen istekle karşılaştırılarak sayılır.
- HA18 — Pazarlık imi üç değerde denenir: hiç bildirim, yalnız biçim, biçim ve dil. Bildirimin doğruluğunu sınayan bir düzenek yoktur; aracı sunucunun saydığı alanlara inanır.
Birinci Ölçüm: Alan Eklemek
İlk ölçüm, önceki iki dersin kurduğu beş kararlık kümeyi olduğu gibi alır ve tek bir şeyi
değiştirir: iletiye aracının çözemediği üç alan eklenir. kahin ve araci işlevlerine
dokunulmaz.
TOHUM = 20260809 GUVENLI = {"GET", "HEAD"} ETKISIZ = {"GET", "HEAD", "PUT", "DELETE"} YONTEMLER = ["GET", "GET", "GET", "HEAD", "POST", "PUT", "DELETE"] YOLLAR = ["/olcum/kuzey", "/olcum/yamac", "/ozet", "/kayit", "/oturum"] BICIMLER = ["json", "json", "csv", "metin", "json"] DILLER = ["tr", "tr", "en", "tr", "en"] KARARLAR = ("saklanabilir", "paylasilabilir", "taze", "yinelenebilir", "yonlendirilebilir") GORUNUR = {"açık": ("yontem", "yol", "konak", "ozel_imi", "dogrulayici")} GORUNUR["açık+ek"] = GORUNUR["açık"] + ("izleme_kimligi", "istemci_surumu", "bolge") def uretec(tohum: int): d = tohum % 2147483646 + 1 def r(n: int) -> int: nonlocal d d = (d * 48271) % 2147483647 return d % n return r def alisverisler(sayi: int = 40, tohum: int = TOHUM) -> list[dict]: r, liste = uretec(tohum), [] for i in range(sayi): yontem, yol = YONTEMLER[r(7)], YOLLAR[r(5)] ozel = yol == "/oturum" or r(5) == 0 degisti = r(3) == 0 liste.append({ "no": i + 1, "yontem": yontem, "yol": yol, "ozel": ozel, "degisti": degisti, "ozel_imi": ozel and r(4) != 0, "damga_atladi": degisti and r(6) == 0, }) return liste def tercih_ata(liste: list[dict], tohum: int = TOHUM + 211) -> list[dict]: r = uretec(tohum) for a in liste: a["bicim"], a["dil"] = BICIMLER[r(5)], DILLER[r(5)] return liste def kahin(a: dict) -> dict: return { "saklanabilir": a["yontem"] in GUVENLI and not a["ozel"], "paylasilabilir": not a["ozel"], "taze": not a["degisti"], "yinelenebilir": a["yontem"] in ETKISIZ, "yonlendirilebilir": True, } def ileti(a: dict, gorunur: tuple) -> dict: tam = {"yontem": a["yontem"], "yol": a["yol"], "konak": "istasyon.ornek", "ozel_imi": a["ozel_imi"], "dogrulayici": a["degisti"] and not a["damga_atladi"], "izleme_kimligi": f"iz-{a['no']:04d}", "istemci_surumu": "olcum-alici", "bolge": "kuzey-yamac"} return {k: v for k, v in tam.items() if k in gorunur} def bayt(i: dict) -> int: return sum(len(k) + len(str(v)) + 4 for k, v in i.items()) def araci(i: dict) -> dict: k = {} if "yontem" in i: k["yinelenebilir"] = i["yontem"] in ETKISIZ if "ozel_imi" in i: k["paylasilabilir"] = not i["ozel_imi"] if "yontem" in i: k["saklanabilir"] = i["yontem"] in GUVENLI and not i["ozel_imi"] if "dogrulayici" in i: k["taze"] = not i["dogrulayici"] if "konak" in i: k["yonlendirilebilir"] = True return k def olc(ad: str, alis: list[dict]) -> tuple: d = y = e = t = b = 0 for a in alis: gercek, verilen = kahin(a), araci(ileti(a, GORUNUR[ad])) eksik = False for karar in KARARLAR: if karar not in verilen: e += 1 eksik = True elif verilen[karar] == gercek[karar]: d += 1 else: y += 1 t += 1 if eksik else 0 b += bayt(ileti(a, GORUNUR[ad])) return d, y, e, t, b def pazarlik(alis: list[dict], im: tuple) -> tuple: """Adres başına kopya saklayan aracı; anahtara yalnız bildirilen alanlar girer.""" depo, dogru, yanlis, imbayt = {}, 0, 0, 0 for a in alis: if not (a["yontem"] in GUVENLI and not a["ozel"]): continue imbayt += bayt({"pazarlik_imi": im}) if im else 0 anahtar = (a["yol"],) + tuple(a[alan] for alan in im) istenen = (a["bicim"], a["dil"]) verilen = depo.setdefault(anahtar, istenen) if verilen == istenen: dogru += 1 else: yanlis += 1 return dogru, yanlis, len(depo), imbayt
Eklenen üç alan bir izleme kimliği, bir istemci sürümü ve bir bölge adıdır. Üçü de gerçek
bilgi taşır ve üçü de araci işlevinde hiçbir dala girmez.
alis = tercih_ata(alisverisler()) print(f"{'görünürlük':<10s} {'doğru':>6s} {'yanlış':>7s} {'alınamayan':>11s} " f"{'fazladan tur':>13s} {'bayt':>6s}") for ad in ("açık", "açık+ek"): d, y, e, t, b = olc(ad, alis) print(f"{ad:<10s} {d:6d} {y:7d} {e:11d} {t:13d} {b:6d}") ba, be = olc("açık", alis)[4], olc("açık+ek", alis)[4] print(f"alan sayısı {len(GORUNUR['açık'])} -> {len(GORUNUR['açık+ek'])}, " f"bayt {ba} -> {be}, artış %{100 * (be - ba) / ba:.0f}, kazanılan karar " f"{olc('açık+ek', alis)[0] - olc('açık', alis)[0]}")
görünürlük doğru yanlış alınamayan fazladan tur bayt açık 195 5 0 0 3524 açık+ek 195 5 0 0 6484 alan sayısı 5 -> 8, bayt 3524 -> 6484, artış %84, kazanılan karar 0
Karar tablosunun dört sütunu da aynı kalır: 195 doğru, 5 yanlış, 0 alınamayan, 0 fazladan tur. Bayt ise 3524’ten 6484’e çıkar — yüzde 84 artış, sıfır karar. Kırk alışverişte iki bin dokuz yüz altmış bayt fazladan taşınmış ve karşılığında hiçbir şey alınmamıştır.
Bu, kursun ikinci iddiasıdır ve ölçüsü burada ödenir: alan eklemek karar kazandırmaz. Bir alanın değeri, taşıdığı bilgiden değil, okuyanın o bilgiyle bir dal kurup kuramadığından gelir. İzleme kimliği ölçüm istasyonu için değerli olabilir; aracı için üç yüz altmış bayttır ve daha fazlası değildir.
İkinci Ölçüm: Pazarlığın Bedeli
İkinci ölçüm ters yöndedir. Şimdi eklenen alan aracının çözebildiği bir alandır ve sorusu şudur: pazarlığa hangi alanın girdiğini bildirmek kaç karar kazandırır.
Aracı, sakladığı kopyayı bir anahtara bağlar. Bildirim yoksa anahtar yalnız adrestir: ilk gelen kopya saklanır ve sonraki her isteğe o verilir. Bildirim varsa anahtara bildirilen alanlar da girer ve her gösterim ayrı saklanır. Ölçüm, yalnız saklanabilir alışverişler üzerinde yürür — yani güvenli yöntemli ve kişiye özel olmayanlar.
Bu bildirimin protokoldeki karşılığı Vary başlık alanıdır: sunucu, yanıtı üretirken
isteğin hangi başlık alanlarına baktığını burada sayar. Modeldeki pazarlik_imi demeti tam
olarak bu listedir. Alanın yanıt tarafında durması da rastlantı değildir — pazarlığa neyin
girdiğini yalnız seçimi yapan taraf bilir, ve aracı ancak kendisine söylenirse bilir.
Listenin uzunluğunun bir sınırı vardır ve bu sınır ölçümün son sütununda görünür. Anahtara giren her alan, saklanan kopya sayısını çarpar. Değeri her istemcide başka olan bir alan listeye girerse her istek ayrı bir anahtar üretir ve aracı hiçbir kopyayı ikinci kez kullanamaz. Doğru bildirim, pazarlığa gerçekten giren alanları sayan ve girmeyenleri saymayan bildirimdir: eksiği yanlış kopya, fazlası hiç kullanılmayan kopya üretir.
saklanan = [a for a in alis if a["yontem"] in GUVENLI and not a["ozel"]] print(f"pazarlığa giren alışveriş {len(saklanan)}, " f"istenen gösterim {len({(a['bicim'], a['dil']) for a in saklanan})} çeşit, " f"adres {len({a['yol'] for a in saklanan})}") print() print(f"{'bildirilen im':<22s} {'doğru kopya':>12s} {'yanlış kopya':>13s} " f"{'saklanan':>9s} {'im baytı':>9s}") for im in ((), ("bicim",), ("bicim", "dil")): d, y, n, ib = pazarlik(alis, im) print(f"{str(im):<22s} {d:12d} {y:13d} {n:9d} {ib:9d}") d0, y0, n0, b0 = pazarlik(alis, ()) d2, y2, n2, b2 = pazarlik(alis, ("bicim", "dil")) print() print(f"tam im: kazanılan karar {d2 - d0}, ödenen bayt {b2 - b0}, " f"karar başına {(b2 - b0) / (d2 - d0):.1f} bayt; " f"saklanan kopya {n0} -> {n2}")
pazarlığa giren alışveriş 13, istenen gösterim 6 çeşit, adres 4
bildirilen im doğru kopya yanlış kopya saklanan im baytı
() 4 9 4 0
('bicim',) 9 4 8 338
('bicim', 'dil') 13 0 11 416
tam im: kazanılan karar 9, ödenen bayt 416, karar başına 46.2 bayt; saklanan kopya 4 -> 11
On üç saklanabilir alışveriş, dört adres ve altı çeşit gösterim isteği vardır. Ölçüm bandının alt sınırı bu kümede ’dir; bundan küçük bir fark iddia edilmez.
Hiçbir bildirim yokken aracı dört kopya saklar ve on üç isteğin dokuzuna yanlış kopyayı verir. Yanlış kopya, bozuk bir yanıt değildir: geçerli, taze, doğru adresten gelmiş bir gösterimdir — yalnız isteyene ait değildir. İsteyen düz metin beklerken yapılandırılmış bir kayıt alır, Türkçe beklerken İngilizce alır.
Yalnız biçim bildirildiğinde yanlış kopya dokuzdan dörde iner. Kalan dördü dil eksenindendir: aracı biçimi ayırmayı öğrenmiş, dili ayırmayı öğrenmemiştir. Eksik bildirim, hiç bildirim yapmamanın küçük bir sürümüdür, çünkü kaçırılan tek bir eksen bile kopyayı yanlış kılmaya yeter. İki eksen birden bildirildiğinde yanlış kopya sıfıra iner.
İki Ölçümün Yan Yana Okunması
İki ölçüm aynı iletiye alan ekliyor ve karşılıkları taban tabana zıt çıkıyor.
| Eklenen | Bayt | Kazanılan karar |
|---|---|---|
| Üç çözülemeyen alan | 2960 | 0 |
| Pazarlık imi | 416 | 9 |
Fark alanların büyüklüğünde değil, okuyanın onlarla ne yapabildiğindedir. Birinci ölçümdeki üç alan aracının koduna hiçbir dal eklemez; ikinci ölçümdeki tek alan aracının anahtarını değiştirir. Bu yüzden ölçü alan sayısı değil karar olmak zorundadır: alan sayısı ikisini de “iletiye bir şey eklendi” diye sayardı.
Pazarlığın ikinci bir bedeli daha vardır ve bu bedel bayt değildir. Bildirim eksiksiz olduğunda aracının sakladığı kopya sayısı dörtten on bire çıkar. Aynı adres artık aracı için tek bir girdi değildir; her gösterim ayrı yer tutar ve ayrı tazelenir. Doğru kopyayı vermenin karşılığı, aynı kaynağı birden çok kez saklamaktır.
Ve dördüncü okuma burada da geçerlidir. Aracı, pazarlığa gerçekten hangi alanların girdiğini sınayamaz. Sunucu eksik bildirirse aracı eksik anahtarla saklar ve yanlış kopyayı hiçbir hata vermeden dağıtır. Bildirimin doğruluğunu denetleyen bir düzenek yoktur; aracı burada da bildirime inanır. Bu derste sayılan bütün kazanç ve bedeller, o tek varsayımın üzerinde durur.
Özet
- Başlık alanları aracı bakımından ikiye ayrılır: çözülüp bir karara bağlananlar ve yalnız taşınanlar.
- Kırk alışverişlik kümede üç çözülemeyen alan eklendiğinde karar tablosu aynı kalır — 195 doğru, 5 yanlış — ama bayt 3524’ten 6484’e, yüzde 84 artar.
- Bir adres bir kaynağı adlandırır; içerik pazarlığı aynı kaynağın biçim, dil ve kodlama eksenlerinde birden çok gösterimi olmasıdır.
- Pazarlığa giren alan bildirilmezse aracı on üç saklanabilir alışverişin dokuzunda yanlış kopyayı verir; yalnız biçim bildirilirse dört, iki eksen de bildirilirse sıfır yanlış kopya kalır.
- Aynı iletiye eklenen 2960 bayt sıfır karar, 416 bayt dokuz karar kazandırır; ölçünün alan sayısı değil karar olmasının nedeni budur.
- Doğru kopyayı vermenin bedeli baytla sınırlı değildir: saklanan kopya sayısı dörtten on bire çıkar.
Sonraki Adım
İçerik pazarlığı, aynı adresin birden çok gösterimi olması demektir ve aracı hangi kopyayı kime vereceğini başlık alanlarından çıkarır. Bu dersin ölçtüğü bütün gösterimlerin ortak bir özelliği vardı: aynı bildirimi yapan iki istemci aynı kopyayı hak ediyordu. Biçim ve dil, isteyenin kim olduğunu değil, ne istediğini anlatır.
Peki yanıt kişiye özelse — yani aynı adrese, aynı biçim ve dil bildirimiyle gelen iki istemcinin farklı yanıtları hak ettiği durumda ne olur? O zaman doğru kopyayı seçmek için gereken alan, artık ne istendiğini değil kime ait olunduğunu taşımak zorundadır. Sonraki ders bu alanı ve aracının onunla ilişkisini ele alacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.