İçeriğe geç
academia.sh

Ders 14 / 16

Dosya Aktarım Protokolleri

Denetim kanalı ile veri kanalının ayrılması: aracı iki kanalı eşleştiremediğinde hangi kararı kaybeder, hangisini yanlış alır, ve bölünmenin bedeli gizlemenin bedelinden nasıl ayrılır.

İçindekiler

Önceki üç ders gerçek zamanlılığın üç yolunu yan yana koydu ve turu karar başına ölçtü. Üçünün ortak bir yanı vardı: hepsi tek bir uygulamanın iki ucu arasındaydı ve hepsi aynı taşıma zarfını (transport envelope) kullanıyordu. Aracı bir tek bağlantıya bakıyor, gördüğünü ya görüyor ya görmüyordu.

Kimi protokol böyle çalışmaz. Bir dosya aktarımı, tek bir mantıksal işi iki ayrı bağlantıya bölebilir: komutlar birinde, dosyanın baytları öbüründe. Bu dersin sorusu şudur: aracı ikisini de görüyorsa ama hangisinin hangisine ait olduğunu söyleyen bir alan yoksa ne kaybeder. Kaybın gizlemekle ilgisi yoktur; bu ders o iki bedeli ayrı ayrı sayar.

  • DG41. Kurgu M04/K03’ün ortak kurgusudur: istasyon.ornek ölçüm istasyonu, arada uygulamayı bilmeyen bir aracı. Aracı yalnız iletide yazana bakar.
  • DG42. Ölçülen küme 40 aktarım ve aktarım başına 5 karardır: yuklemedir, yeniden_denenebilir, olcum_dosyasi, surdurulur, tamamlandi. Toplam 200 karar; bu kümede ölçülebilen en küçük fark 1/200=0,00501/200 = 0{,}0050’dir.
  • DG43. Kâhin — gerçeğin kendisi — kurguyu biz ürettiğimiz için bilinir ve rejimden rejime değişmez. Rejim yalnız aracının gördüğü alanları değiştirir.
  • DG44. Dört rejim kurulur: iki kanal açık, veri kanalı zarflı, tek kanal açık, tek kanal zarflı. Aktarımların kendisi dört rejimde de aynıdır.
  • DG45. Aktarım araçlarının kullanımı burada tekrarlanmaz. Uzak kabuk, anahtar taşıma ve eşitleme yordamı Linux Ağ Yönetimi ve Sorun Giderme kursunda ölçüldü; buradaki ölçü kanal ayrımıdır, araç değil.

Denetim Kanalı ve Veri Kanalı

Dosya aktarımının klasik biçimi iki kanal tanımlar. Denetim kanalı (control channel) komutları ve yanıt kodlarını taşır; oturum boyunca açık kalır. Veri kanalı (data channel) yalnız dosyanın ya da dizin dökümünün baytlarını taşır; her aktarım için açılır ve aktarım bitince kapanır. FTP bu ayrımı yapan belirtimdir.

denetim kanalı — istemci ile istasyon.ornek arasında, oturum boyunca açık

  ->  USER olcum
  <-  331 parola bekleniyor
  ->  PASS ********
  <-  230 oturum açıldı
  ->  TYPE I
  <-  200 tür ikili
  ->  PASV
  <-  227 edilgen kip (a1,a2,a3,a4,p1,p2)
  ->  SIZE /olcum/kuzey.csv
  <-  213 9216
  ->  RETR /olcum/kuzey.csv
  <-  150 veri kanalı açılıyor
  <-  226 aktarım tamam

veri kanalı — ayrı bir bağlantı, aktarım süresince

  9216 bayt akar. Komut yok, yol yok, oturum imi yok; bitişte bağlantı kapanır.

Bu döküm çalıştırılmadı; öğretilen biçimdir. İki nokta okunmalıdır. Birincisi, veri kanalının nereye açılacağı denetim kanalının gövdesinde pazarlık edilir: PORT ile istemci kendi dinlediği yeri bildirir, PASV ile sunucu kendi açtığı yeri bildirir. İkincisi, veri kanalında akan baytların üzerinde hangi komuta ait olduğunu söyleyen hiçbir alan yoktur.

Karşı uçta duran iki tasarım vardır. SFTP tek bir bağlantı kurar, o bağlantıyı bir zarfın içine alır ve komutları da baytları da aynı bağlantı üzerinde çerçeveler; her isteğin bir istek imi vardır ve yanıt o imle döner. FTPS iki kanallı düzeni korur ama her kanalı ayrı ayrı zarfa alır — ve “ayrı ayrı” burada anahtar sözcüktür.

Sürdürme ve Dizin Dökümü

Ölçülen beş karardan ikisi bu iki ayrıntıdan doğuyor, o yüzden önce onlar kurulmalı.

Sürdürme. Yarıda kesilmiş bir aktarım iki türlü tamamlanabilir: baştan ya da kaldığı yerden. Kaldığı yerden sürdürme, istemcinin bir başlangıç konumu bildirip komutu yinelemesiyle olur; belirtimde bunun komutu REST’tir. Sunucunun sürdürmeyi destekleyip desteklemediği ise denetim kanalında bildirilen bir yetenektir ve bildirimi doğrulayan hiçbir şey yoktur. Aracı için bu kararın somut bir bedeli var: sürdürülebiliyorsa kesilen bir aktarım yalnız kalan baytlara mal olur, sürdürülemiyorsa dosyanın tamamı yeniden akar. Ölçümde her aktarım tek bir denemedir; sürdürmenin bayt muhasebesine etkisi ayrıca not edilmelidir, çünkü sürdürülen bir aktarımda veri kanalında akan bayt sayısı bildirilen boyuttan küçüktür ve boyut karşılaştırmasına bakan bir aracı başarılı bir aktarımı eksik sanır.

Dizin dökümü. LIST komutunun veri kanalında döndürdüğü dizin listesinin biçimi belirtimde sabitlenmemiştir; insan okusun diye tasarlanmıştır. Sonuç, kursun kuralının en keskin biçimidir: alan vardır ama anlamı yoktur. Aracı baytları görür, satırları bile ayırabilir, ama hangi sütunun boyut hangisinin ad olduğuna dair güvenebileceği bir sözleşme yoktur. Belirtim bu boşluğu sonradan makinenin okuyacağı bir döküm komutuyla — MLSD — kapatır; kapatma yolu yeni bir bayt değil, adı ve anlamı sabitlenmiş alanlardır. Ölçümde LIST bu yüzden yeniden_denenebilir tarafında RETR ile aynı sınıfta durur: ikisi de istasyonun durumunu değiştirmez.

Aracının Elindeki Alanlar

Aracı denetim kanalından komutu, yolu, sunucunun bildirdiği boyutu ve sürdürme desteğini okur. Veri kanalından yalnız bir bayt sayısı okur. Bu iki gözlemi birleştirmek için elinde tek bir şey vardır: zaman yakınlığı. Komuttan hemen sonra açılan bağlantıyı o komutun bağlantısı sayar.

Yakınlık bir imin yerini tutmaz. Aynı istasyona başka bir oturum da bağlanmışsa, aracının bitişik saydığı bağlantı bir başkasının olabilir. Ölçüm bunu sayar.

Etkin ve edilgen kip arasındaki fark aracı açısından bir yön farkıdır: etkin kipte veri bağlantısını sunucu açar, edilgen kipte istemci. Aracı ikisini de görür, ama gördüğü şey bir bağlantı kurulumudur, bir komut değil. Bağlantıyı kimin açtığı ile baytların hangi yöne aktığı ayrı iki şeydir ve birincisinden ikincisi çıkarılamaz. Baytların yönü yalnız denetim kanalındaki komuttan okunur: RETR indirir, STOR yükler. Ölçümdeki yuklemedir kararının tek kaynağı budur ve komut görünmez olduğunda o karar da gider — dördüncü rejimin sıfırı bu yüzden sıfırdır.

TOHUM = 20260809
KOMUTLAR = ["RETR", "RETR", "STOR", "LIST", "RETR", "STOR", "RETR"]
YOLLAR = ["/olcum/kuzey.csv", "/olcum/yamac.csv", "/ozet.csv",
          "/kayit.log", "/olcum/gunluk.csv"]
KARARLAR = ("yuklemedir", "yeniden_denenebilir", "olcum_dosyasi",
            "surdurulur", "tamamlandi")


def uretec(tohum):
    d = tohum % 2147483646 + 1

    def r(n):
        nonlocal d
        d = (d * 48271) % 2147483647
        return d % n
    return r


def aktarimlar(sayi=40, tohum=TOHUM):
    r, liste = uretec(tohum), []
    for i in range(sayi):
        komut, yol = KOMUTLAR[r(7)], YOLLAR[r(5)]
        bildirilen = 1024 * (1 + r(9))
        kesildi = r(5) == 0
        surdurulur = r(3) != 0
        liste.append({
            "no": i + 1, "komut": komut, "yol": yol,
            "bildirilen": bildirilen,
            "gelen": bildirilen - 512 if kesildi else bildirilen,
            "surdurulur": surdurulur,                    # kâhin
            "surdurme_imi": surdurulur and r(7) != 0,    # bildirim
            "komsu_oturum": r(5) == 0,                   # bitişik bağlantı başkasının
            "komsu_bayt": 1024 * (1 + r(9)),
        })
    return liste


def kahin(a):
    return {
        "yuklemedir": a["komut"] == "STOR",
        "yeniden_denenebilir": a["komut"] in ("RETR", "LIST"),
        "olcum_dosyasi": a["yol"].startswith("/olcum/"),
        "surdurulur": a["surdurulur"],
        "tamamlandi": a["gelen"] == a["bildirilen"],
    }


def ileti(a, gorunur):
    tam = {
        "komut": a["komut"], "yol": a["yol"], "konak": "istasyon.ornek",
        "surdurme_imi": a["surdurme_imi"], "bildirilen": a["bildirilen"],
        "bitisik_bayt": a["komsu_bayt"] if a["komsu_oturum"] else a["gelen"],
        "kanal_bayt": a["gelen"], "oturum_imi": a["no"],
    }
    return {k: v for k, v in tam.items() if k in gorunur}


def araci(i):
    k = {}
    if "komut" in i:
        k["yuklemedir"] = i["komut"] == "STOR"
        k["yeniden_denenebilir"] = i["komut"] in ("RETR", "LIST")
    if "yol" in i:
        k["olcum_dosyasi"] = i["yol"].startswith("/olcum/")
    if "surdurme_imi" in i:
        k["surdurulur"] = i["surdurme_imi"]
    if "bildirilen" in i:
        if "oturum_imi" in i:
            k["tamamlandi"] = i["kanal_bayt"] == i["bildirilen"]
        elif "bitisik_bayt" in i:
            k["tamamlandi"] = i["bitisik_bayt"] == i["bildirilen"]
    return k


DENETIM = ("komut", "yol", "konak", "surdurme_imi", "bildirilen")
GORUNUR = {
    "iki kanal açık": DENETIM + ("bitisik_bayt",),
    "veri zarflı": DENETIM,
    "tek kanal açık": DENETIM + ("kanal_bayt", "oturum_imi"),
    "tek kanal zarflı": ("konak",),
}


def olc(ad):
    dogru = yanlis = alinamayan = tur = 0
    dokum = {}
    for a in aktarimlar():
        gercek, verilen = kahin(a), araci(ileti(a, GORUNUR[ad]))
        eksik = False
        for karar in KARARLAR:
            if karar not in verilen:
                alinamayan += 1
                eksik = True
            elif verilen[karar] == gercek[karar]:
                dogru += 1
            else:
                yanlis += 1
                dokum[karar] = dokum.get(karar, 0) + 1
        tur += 1 if eksik else 0
    return dogru, yanlis, alinamayan, tur, dokum


print(f"{'rejim':<17s} {'doğru':>6s} {'yanlış':>7s} {'alınamayan':>11s} "
      f"{'tur':>4s}  yanlış dökümü")
for ad in GORUNUR:
    d, y, e, t, dk = olc(ad)
    print(f"{ad:<17s} {d:6d} {y:7d} {e:11d} {t:4d}  {dk}")

a = aktarimlar()
print()
print(f"aktarım {len(a)}, karar {len(a) * len(KARARLAR)}, "
      f"yarıda kesilen {sum(x['gelen'] != x['bildirilen'] for x in a)}, "
      f"imsiz kalan {sum(x['surdurulur'] and not x['surdurme_imi'] for x in a)}, "
      f"komşu oturum {sum(x['komsu_oturum'] for x in a)}")
rejim              doğru  yanlış  alınamayan  tur  yanlış dökümü
iki kanal açık       192       8           0    0  {'tamamlandi': 3, 'surdurulur': 5}
veri zarflı          155       5          40   40  {'surdurulur': 5}
tek kanal açık       195       5           0    0  {'surdurulur': 5}
tek kanal zarflı       0       0         200   40  {}

aktarım 40, karar 200, yarıda kesilen 7, imsiz kalan 5, komşu oturum 6

Bölünmenin Bedeli Gizlemenin Bedeli Değildir

İlk satır ile üçüncü satır aynı miktarda alanı görüyor: aynı komut, aynı yol, aynı bildirilen boyut, aynı bayt sayısı. Hiçbir şey gizlenmemiş. Yine de iki kanallı rejim 192 doğru karar alırken tek kanallı rejim 195 alıyor. Aradaki 3 karar yalnız ve yalnız bölünmeden geliyor: tek kanalda baytlar çerçevelenip oturum imi taşıdığı için eşleştirme kurulum gereği doğrudur, iki kanalda ise aracı komşu oturumun bağlantısını bu komutun bağlantısı sanmıştır. 3/200 = 0,015; kümenin çözünürlüğünün üç katı, dolayısıyla ölçülmüş bir farktır.

Sayının okunmasında bir incelik var. Komşu oturum 6 aktarımda araya giriyor ama yanlış karar yalnız 3 tanesinde doğuyor. Kalan üçünde aktarımın kendisi zaten yarıda kesilmiştir: aracı “tamamlanmadı” der, kâhin de “tamamlanmadı” der, karar doğru çıkar. Aracı doğru cevabı yanlış gerekçeyle vermiştir. Ölçüm bunu doğru sayar, çünkü ölçtüğümüz şey karardır; ama tasarım açısından bu bir güvence değil, iki hatanın birbirini örtmesidir.

İkinci satır bambaşka bir şey söylüyor. Veri kanalı zarfa alındığında aracı bayt sayısını hiç göremez, tamamlandi kararını hiç alamaz ve 40 aktarımın kırkında da sunucuya bir tur daha borçlanır. Burada bir yanlış anlaşılma kapatılmalı: zarflı bir bağlantıda tel üzerinde yine bir bayt sayısı vardır, ama o sayı dosyanın boyutu değildir — zarfın kayıt başlıkları ve dolgusu da o toplamın içindedir. Aracının elindeki sayı ile denetim kanalındaki bildirilen boyut aynı birimde bile değildir; bu yüzden karar yanlış çıkmaz, hiç çıkmaz. Karşılığında 3 yanlış karar ortadan kalkar: kalan 5 yanlışın hepsi başka bir kaynaktan gelir. Bu, kursun üçüncü iddiasının bu derse düşen biçimidir — az karar, ama daha az yanlış. Zarf bir kusur değil bir seçimdir ve seçimin adı şudur: tur borcu ödenir, yanlış eşleştirme satın alınmaz.

Kalan 5 yanlışın kaynağı ise ne bölünmedir ne zarf. Beş aktarımda sunucu sürdürmeyi gerçekten destekler ama denetim kanalında bunu bildirmemiştir. Aracı bildirime bakar, “sürdürülemez” der ve yanılır. Bu, kursun her dersinde tekrarlanan dördüncü okumadır: iletide yazanı doğrulayan hiçbir şey yoktur. Alan eksikse aracı bilmez; yanlışsa yanlış bilir. Bu beş yanlış dört rejimin üçünde de aynı beştir — bölmek de gizlemek de onu ne artırır ne azaltır.

Güvensiz Seçenek Neden Güvensiz

Temel belirtim, denetim kanalını da veri kanalını da hiçbir zarf olmadan taşır. Sonucu şudur: yol boyunca duran her aygıt, oturum açarken geçen kimlik bilgisini, istenen dosya yollarını, bildirilen boyutları ve dosyanın kendi baytlarını okuyabilir. Bu bir kusur değil, belirtimin yazıldığı varsayımdır — yolun kendisinin güvenilir olduğu bir ağ varsayılmıştı. Varsayım tutmadığında protokolde onu kapatacak bir alan yoktur.

Bölünmenin buraya eklediği ikinci bir nokta var: iki kanal ayrı ayrı korunur. Denetim kanalı zarfa alınıp veri kanalı açık bırakılan bir kurulumda istemci oturumunu korunmuş sanır, oysa dosyanın baytları korunmasızdır. Ölçümün ikinci satırı bunun aynadaki görüntüsüdür: orada veri kanalı zarflıdır ve denetim kanalı açıktır; aracı yolu ve boyutu okumaya devam eder. İki kanallı tasarımda “korunuyor mu” sorusunun tek bir yanıtı yoktur, kanal başına bir yanıtı vardır.

Üçüncü nokta yapısaldır. Veri kanalının adresi denetim kanalının gövdesinde pazarlık edildiği için, adres dönüştüren bir aracının o gövdeyi okuyup yeniden yazması gerekir. Denetim kanalı zarfa alındığında bunu yapamaz; aktarım kurulamaz ya da yapılandırma bir bağlantı noktası aralığını sürekli açık tutmak zorunda kalır. Gizlemek ile ortadaki cihazın işini yapabilmesi burada doğrudan çelişir.

Daraltma. Sayılan üç yüzeyin üçünü de kapatan yön aynıdır: kanal sayısını bire indirmek. Tek bağlantı zarfın içine alındığında kimlik bilgisi, yol, boyut ve dosya baytları tek bir kararla korunur; çerçeveleme eşleştirmeyi kurulum gereği çözer, dolayısıyla üç yanlış karar hiç doğmaz; ve gövdede adres pazarlığı olmadığı için ortadaki cihazın gövdeyi yeniden yazması gerekmez. SFTP bu yöndedir. İki kanallı düzenin korunması gerekiyorsa daraltma, her iki kanalın korunmasının ayrı ayrı ve açıkça istenmesidir; birinin zarflı olması öbürü hakkında hiçbir şey söylemez. Ölçümün son satırı bedeli de yazıyor: tek kanal zarflı rejimde aracı 200 kararın tamamını kaybeder. Aracının önbelleklemesi, yeniden denemesi ve boyut denetimi bu rejimde yoktur; o işler uçlara döner.

Özet

  • Klasik dosya aktarımı bir işi iki bağlantıya böler: denetim kanalı komutları ve yanıt kodlarını, veri kanalı yalnız baytları taşır; baytların üzerinde hangi komuta ait olduğunu söyleyen alan yoktur.
  • 40 aktarımlık 200 kararlık kümede iki kanallı açık rejim 192 doğru, tek kanallı açık rejim 195 doğru karar veriyor; aradaki 3 karar yalnız bölünmeden gelir, gizlemeden değil.
  • Komşu oturum 6 aktarımda araya giriyor ama yanlış karar 3’te doğuyor; kalan üçünde aktarım zaten yarıda kesildiği için aracı doğru cevabı yanlış gerekçeyle verir.
  • Veri kanalı zarfa alındığında tamamlandi kararı 40 kez alınamaz ve 40 tur borcu doğar; buna karşılık 3 yanlış karar ortadan kalkar — az karar, ama daha az yanlış.
  • Beş yanlış karar üç rejimde de aynıdır ve kaynağı sunucunun sürdürme desteğini bildirmemesidir; bölmek de gizlemek de bildirimin eksikliğini onarmaz.
  • Zarfsız temel belirtimde kimlik bilgisi, yol, boyut ve dosya baytları yol boyunca okunabilir; iki kanal ayrı ayrı korunduğu için “korunuyor mu” sorusunun kanal başına bir yanıtı vardır ve daraltma kanal sayısını bire indirmektir.

Sonraki Adım

Bu derste ayrılan şey iki kanaldı: birinde ne istendiği yazıyordu, öbüründe ne geldiği. Aracı ikisini eşleştiremediğinde bir kararı yanlış aldı. Sonraki derste ayrılan şey iki ad olacak. Bir postanın nereye teslim edileceğini söyleyen alanlar ile kullanıcıya kimden geldiği gösterilen alanlar aynı iletide durur, birbirini doğrulamaz ve teslimi yönlendiren zarfa bakılır. Aracının yönlendirme için okuduğu ad ile insanın ekranda gördüğü ad ayrı iki alandan gelir; sonraki ders bu ayrımın neden var olduğunu ve hangi denetimin onu kapattığını ölçer.

İ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