İçeriğe geç
academia.sh

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. kahin ve araci iş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 1/13=0,0771/13 = 0{,}077’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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat