---
title: 'Yerel Sunucuya Bağlanma'
source: 'https://academia.sh/tr/kurslar/mcp/yerel-sunucuya-baglanma'
course: 'Model Bağlam Protokolü ve Araç Ekosistemi'
language: tr
updated: '2026-08-17T18:06:40+00:00'
license: 'CC BY-SA 4.0'
---

# Yerel Sunucuya Bağlanma

Yerel bir sunucunun ayrı bir süreç olarak başlatılması ve bağlantının bedelinin ilk çağrıya kadar geçen mesajla sayılması: süreci başlatmak hazır bildirimiyle 1 mesaj ve 10 belirteç, sunucu keşfi 6 mesaj ve 99 belirteç tutar, yani ilk araç çağrısı gönderilmeden önce 7 mesaj ve 109 belirteç harcanır. Aynı kurulumun ardından koşan üç araçlık zincir 3 istek, 3 yanıt, 80 belirteç ve 4 gidiş-dönüşle A017 abonesi için 844 verir; kurulum tek görevlik bir oturumda işten pahalıdır. On iki görevde kurulum 7 mesajda kalırken iş 60 mesaja çıkar. Süreç düştüğünde ne hata ne mesaj üretilir, kayıp yalnız sonraki çağrının gönderilememesiyle anlaşılır ve toparlanma kurulumun tamamını yeniden ödetir: bir düşme belirteci 919'dan 1028'e, üç düşme 1246'ya çıkarır, tamamlanan görev on ikide kalır.

Önceki iki derste sunucu ve istemci yazıldı: yetenek bildiriminin eksiksizliği çağrılabilirlik
olarak sayıldı, keşfin bedeli çıkarıldı ve sürüm sapmasıyla düşen aracın hiçbir hata üretmediği
görüldü. İkisi de tek bir varsayımın üstünde duruyordu. Sunucu **oradaydı**: yetenek sorulduğunda
yanıt veriyordu, çağrı gönderildiğinde karşılıyordu.

Yerel bir sunucu için bu varsayım kurulmaz, **kurulur**. Yerel sunucu aynı makinede çalışan ayrı
bir süreçtir: birinin onu başlatması gerekir, hazır olduğunu söylemesi gerekir ve öldüğünde
oturumun tuttuğu her şey onunla birlikte gider. Bu dersin sorusu şudur: ilk işe yarar çağrı
gönderilene kadar kaç mesaj geçer, o zincir ne tutar, ve süreç düştüğünde kim yeniden öder.

- **GE20.** Ortam, üç sunucu, süreç ve protokol benzeticisi **kurgudur**; gerçek bir süreç
  başlatılmaz, gerçek bir sunucu ya da çalışma zamanı çağrılmaz. Tohum **20260218**, ikinci
  koşum **20260219**.
- **GE21.** `olcum` sunucusu yereldir ve bir süreçtir. `tarife` ile `kayit` uzaktır; bağlantı
  biçimleri sonraki derse bırakılır, burada yalnız zincirin içinde yer alırlar.
- **GE22.** Süreç başlatıldığında sunucu hazır olduğunu bir **bildirim mesajıyla** söyler. Bildirim
  yanıt beklemez: zarf bedelini öder ama gidiş-dönüş **eklemez**.
- **GE23.** Sunucu keşfi süreç başlatıldıktan sonra yapılır. Kurulum, süreç başlatma ile keşfin
  toplamıdır.
- **GE24.** Süreci kapalı bir yerel sunucuya yapılan çağrı **hiç gönderilemez**; istemcinin kendi
  içinde `surec kapali` ile biter ve mesaj harcamaz.
- **GE25.** Süreç **sessizce** ölür: ölüm ne bir hata ne bir mesaj üretir. İstemci bunu ancak
  sonraki çağrıyı gönderemediğinde anlar.
- **GE26.** Toparlanma şudur: süreç yeniden başlatılır, oturum baştan kurulur ve başarısız çağrı
  bir kez yinelenir. Kurulumun tamamı yeniden ödenir.
- **GE27.** Görev kümesi 12 kurgu görevdir; iki türden altışar tane (bedel ve tüketim). Bu kümede
  bütün araçlar anlaşılan kümededir, böylece değişen tek şey süreçtir.
- **GE28.** Zarfın sabit bedeli 8 belirteçtir; uzak aktarımda gidiş-dönüş iki katıdır.
- **GE29.** Taban çizgisi protokolsüz kurulumdur: aracın ders içinde tanımlandığı, başlatılacak bir
  süreç ve sorulacak bir yetenek olmadığı hâl. Orada kurulum bedeli sıfırdır.

## Süreç, Hazır Bildirimi ve İlk Çağrı

Aşağıdaki kod kurgu ortamı, üç kurgu sunucuyu ve yetenek uzlaşmasını kurar, sonra yerel sunucuyu
bir sürece bağlar: `baslat` süreci açar ve hazır bildirimini gönderir, `cagir_yerel` süreci kapalı
bir sunucuya çağrı gönderilmesini engeller, `kurulum` ikisini birleştirir.

```python
TOHUM, M32 = 20260218, 0xFFFFFFFF


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def belirtecle(m):
    b = []
    for s in str(m).lower().replace(",", " , ").split():
        while len(s) > 5:
            b.append(s[:5])
            s = s[5:]
        b.append(s)
    return b


# ---- KURGU ortam ve araclar (K05 ile ayni kurgu, burada sunucuya tasiniyor)
BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
ABONE = {}
for i in range(60):
    r = uretec(TOHUM + 31 * i)
    onceki = 10000 + int(r() * 80000)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "onceki": onceki, "simdiki": onceki + int(r() * 70)}
BASAMAK, USTU, ISYERI_KAT = ((10, 4), (25, 7), (40, 11)), 16, 2


def _bedel(m3, tip):
    kalan, alt, top = m3, 0, 0
    for ust, birim in BASAMAK:
        dilim = min(kalan, ust - alt)
        if dilim <= 0:
            break
        top += dilim * birim
        kalan -= dilim
        alt = ust
    return (top + kalan * USTU) * (ISYERI_KAT if tip == "isyeri" else 1)


def t_sayac(abone=None, **_):
    a = ABONE.get(abone)
    return {"hata": "abone yok"} if a is None else {
        "onceki": a["onceki"], "simdiki": a["simdiki"], "tip": a["tip"]}


def t_tuketim(onceki=None, simdiki=None, **_):
    if onceki is None or simdiki is None:
        return {"hata": "eksik alan"}
    f = simdiki - onceki
    return {"m3": f + 100000 if f < 0 else f}


def t_tarife(m3=None, tip="mesken", **_):
    return {"hata": "eksik alan"} if m3 is None else {"tutar": _bedel(m3, tip)}


def t_bolge(bolge=None, **_):
    if bolge not in BOLGE:
        return {"hata": "bolge yok"}
    n = sum(1 for a in ABONE.values() if a["bolge"] == bolge)
    return {"bolge": bolge, "abone": n}


def t_kayit(abone=None, sutun=None, deger=None, **_):
    if not (abone and sutun and deger is not None):
        return {"hata": "eksik alan"}
    return {"yazildi": True}


# ---- KURGU sunucular: olcum yerel bir surec , otekiler uzak
SUNUCU = {
    "olcum": {"surum": 2, "aktarim": "yerel",
              "arac": {"sayac_oku": {"islev": t_sayac, "alan": ("abone",), "yan_etki": False},
                       "tuketim": {"islev": t_tuketim, "alan": ("onceki", "simdiki"),
                                   "yan_etki": False}},
              "kaynak": ("abone_listesi",), "istem": ()},
    "tarife": {"surum": 1, "aktarim": "uzak",
               "arac": {"tarife": {"islev": t_tarife, "alan": ("m3", "tip"), "yan_etki": False}},
               "kaynak": ("basamak_tablosu",), "istem": ("bedel_aciklamasi",)},
    "kayit": {"surum": 3, "aktarim": "uzak",
              "arac": {"bolge_ozet": {"islev": t_bolge, "alan": ("bolge",), "yan_etki": False},
                       "kayit_yaz": {"islev": t_kayit, "alan": ("abone", "sutun", "deger"),
                                     "yan_etki": True}},
              "kaynak": (), "istem": ()},
}
ISTEMCI_SURUM = {"olcum": 2, "tarife": 1, "kayit": 2}      # kayit sunucusu ileride
IZIN = ("sayac_oku", "tuketim", "tarife", "bolge_ozet")     # kayit_yaz izin listesinde yok

SAYIM = {"istek": 0, "yanit": 0, "bildirim": 0, "belirtec": 0, "gidis_donus": 0}


def mesaj(tur, govde, aktarim="yerel"):
    """KURGU zarf. Gercek bir protokol uygulanmaz; sayilan sey zarfin bedelidir."""
    SAYIM[tur] += 1
    b = len(belirtecle(govde)) + 8                       # zarf sabiti
    SAYIM["belirtec"] += b
    if tur == "istek":
        SAYIM["gidis_donus"] += 2 if aktarim == "uzak" else 1
    return b


def elsikismasi(istemci_surum=None, izin=None):
    """Yetenek uzlasmasi: surum uyusmazligi ve izin listesi arac kumesini daraltir."""
    istemci_surum = ISTEMCI_SURUM if istemci_surum is None else istemci_surum
    izin = IZIN if izin is None else izin
    anlasilan, dusen = {}, []
    for ad, s in SUNUCU.items():
        mesaj("istek", f"yetenek sor {ad}", s["aktarim"])
        mesaj("yanit", f"yetenek bildir {ad} surum {s['surum']} "
                       + " ".join(s["arac"]) + " " + " ".join(s["kaynak"]))
        if istemci_surum.get(ad, 0) < s["surum"]:
            dusen.append((ad, "surum", s["surum"], istemci_surum.get(ad, 0)))
            continue
        for t, tan in s["arac"].items():
            if t not in izin:
                dusen.append((ad, "izin", t, None))
                continue
            anlasilan[t] = dict(tan, sunucu=ad, aktarim=s["aktarim"])
    return anlasilan, dusen


def cagir(anlasilan, ad, durum):
    if ad not in anlasilan:
        return {"hata": "arac bildirilmedi"}
    t = anlasilan[ad]
    kw = {a: durum[a] for a in t["alan"] if a in durum}
    mesaj("istek", f"{ad} " + " ".join(f"{k} {v}" for k, v in kw.items()), t["aktarim"])
    s = t["islev"](**kw)
    mesaj("yanit", " ".join(f"{k} {v}" for k, v in s.items()))
    return s


# ---- Yerel sunucu bir surectir: baslatilir , hazir oldugunu bildirir , olur
SUREC = {ad: False for ad, s in SUNUCU.items() if s["aktarim"] == "yerel"}


def baslat(ad):
    """Sureci baslatir; sunucu hazir oldugunu yanit beklemeyen bir bildirimle soyler."""
    SUREC[ad] = True
    mesaj("bildirim", f"{ad} hazir")


def cagir_yerel(anlasilan, ad, durum):
    """Sureci kapali bir yerel sunucuya cagri hic gonderilemez."""
    t = anlasilan.get(ad)
    if t is not None and SUREC.get(t["sunucu"]) is False:
        return {"hata": "surec kapali"}
    return cagir(anlasilan, ad, durum)


def kurulum(istemci_surum=None):
    """Yerel surec + sunucu kesfi: ilk cagriya kadar gecen her sey."""
    for k in SAYIM:
        SAYIM[k] = 0
    for ad in SUREC:
        baslat(ad)
    anlasilan = elsikismasi(istemci_surum)[0]
    return anlasilan, dict(SAYIM)


anlasilan, k = kurulum()
print(f"ilk cagriya kadar : bildirim {k['bildirim']} , istek {k['istek']} ,"
      f" yanit {k['yanit']} , toplam mesaj {k['bildirim'] + k['istek'] + k['yanit']} ,"
      f" belirtec {k['belirtec']} , gidis-donus {k['gidis_donus']}")
for key in SAYIM:
    SAYIM[key] = 0
durum = {"abone": "A017"}
for ad in ("sayac_oku", "tuketim", "tarife"):
    durum.update(cagir_yerel(anlasilan, ad, durum))
print(f"ilk zincir ( A017 ) : istek {SAYIM['istek']} , yanit {SAYIM['yanit']} ,"
      f" belirtec {SAYIM['belirtec']} , gidis-donus {SAYIM['gidis_donus']} ,"
      f" sonuc {durum['tutar']}")
```

```
ilk cagriya kadar : bildirim 1 , istek 3 , yanit 3 , toplam mesaj 7 , belirtec 109 , gidis-donus 5
ilk zincir ( A017 ) : istek 3 , yanit 3 , belirtec 80 , gidis-donus 4 , sonuc 844
```

İlk satır bu dersin ana ölçüsüdür. Bir araç çağrısı gönderilmeden önce **7 mesaj** ve
**109 belirteç** harcanmıştır: süreç başlatma bildirimi bir mesaj ve 10 belirteç, sunucu keşfi altı
mesaj ve 99 belirteç. Hazır bildirimi zarf bedelini ödüyor ama gidiş-dönüşe hiç dokunmuyor, çünkü
yanıt beklemiyor; beşin tamamı keşfin gidiş-dönüşüdür.

İkinci satır aynı kurulumun üstünde koşan zincirdir ve karşılaştırma buradan çıkar. Üç araçlık
zincir **3 istek, 3 yanıt, 80 belirteç, 4 gidiş-dönüş** tutuyor ve A017 abonesi için **844**
veriyor. Üç istek için dört gidiş-dönüş sayılmasının nedeni zincirin ikiye bölünmüş olmasıdır:
`sayac_oku` ile `tuketim` yerel süreçle konuşur ve birer gidiş-dönüş sayar, `tarife` uzaktadır ve
iki sayar. Tek görevlik bir oturumda kurulum işten **pahalıdır**: 7 mesaja karşı 6, 109 belirtece
karşı 80. Protokolsüz kurulumda bu 109 belirtecin karşılığı sıfırdır, çünkü başlatılacak süreç de
sorulacak yetenek de yoktur.

## Süreç Düşerse Kim Öder

Aşağıdaki kod on iki kurgu görevi aynı süreç üzerinde koşturur. Görevlerin hepsi anlaşılan araç
kümesiyle çözülebilir, böylece değişen tek şey sürecin ayakta kalıp kalmadığı olur. Süreç
belirlenmiş görev sıralarında sessizce ölür.

```python
ZINCIR = {"bedel": ("sayac_oku", "tuketim", "tarife"), "tuketim": ("sayac_oku", "tuketim")}


def gorevler(n=12, tohum=TOHUM):
    """KURGU gorevler: iki turden esit sayida, abonesi tohumla secilir."""
    g = []
    for i in range(n):
        r = uretec(tohum + 9973 * i)
        g.append({"tur": list(ZINCIR)[i % 2], "abone": f"A{1 + int(r() * 60):03d}"})
    return g


def dogru(g):
    a = ABONE[g["abone"]]
    f = a["simdiki"] - a["onceki"]
    m3 = f + 100000 if f < 0 else f
    return m3 if g["tur"] == "tuketim" else _bedel(m3, a["tip"])


def toparla(oturum):
    """Dusen surec yeniden baslatilir ve oturum bastan kurulur: kesif yeniden odenir."""
    for ad, acik in SUREC.items():
        if not acik:
            baslat(ad)
    oturum["anlasilan"] = elsikismasi()[0]
    oturum["yeniden"] += 1


def yurut(oturum, g):
    durum, sonuc = {"abone": g["abone"]}, None
    for ad in ZINCIR[g["tur"]]:
        y = cagir_yerel(oturum["anlasilan"], ad, durum)
        if y.get("hata") == "surec kapali":
            toparla(oturum)
            y = cagir_yerel(oturum["anlasilan"], ad, durum)
        if "hata" in y:
            break
        durum.update(y)
        sonuc = y.get("tutar", y.get("m3", sonuc))
    return sonuc == dogru(g)


def kosum(n=12, dusme=(), tohum=TOHUM):
    """Ayni gorevler; degisken, surecin kac kez dustugu."""
    for ad in SUREC:
        SUREC[ad] = False
    anlasilan, k = kurulum()
    oturum = {"anlasilan": anlasilan, "yeniden": 0}
    tamam = 0
    for i, g in enumerate(gorevler(n, tohum)):
        if i in dusme:
            SUREC["olcum"] = False               # surec sessizce oluyor , mesaj yok
        tamam += yurut(oturum, g)
    return dict(yeniden=oturum["yeniden"], tamam=tamam, **SAYIM)


print("kurulum                     yeniden bildirim istek yanit belirtec gidis tamamlanan")
for ad, n, dus in (("1 gorev , dusme yok", 1, ()), ("12 gorev , dusme yok", 12, ()),
                   ("12 gorev , 1 surec dusmesi", 12, (4,)),
                   ("12 gorev , 3 surec dusmesi", 12, (2, 5, 9))):
    a = kosum(n, dus)
    print(f"{ad:<28} {a['yeniden']:>5} {a['bildirim']:>8} {a['istek']:>6} {a['yanit']:>5}"
          f" {a['belirtec']:>8} {a['gidis_donus']:>5} {a['tamam']:>10}")
b = kosum(12, (4,), TOHUM + 1)
print("ikinci kosum ( gorev tohumu 20260219 , 1 dusme ) :", dict(
    tamamlanan=b["tamam"], mesaj=b["bildirim"] + b["istek"] + b["yanit"], belirtec=b["belirtec"]))
```

```
kurulum                     yeniden bildirim istek yanit belirtec gidis tamamlanan
1 gorev , dusme yok              0        1      6     6      189     9          1
12 gorev , dusme yok             0        1     33    33      919    41         12
12 gorev , 1 surec dusmesi       1        2     36    36     1028    46         12
12 gorev , 3 surec dusmesi       3        4     42    42     1246    56         12
ikinci kosum ( gorev tohumu 20260219 , 1 dusme ) : {'tamamlanan': 12, 'mesaj': 74, 'belirtec': 1028}
```

İlk iki satır kurulumun nasıl seyreldiğini gösteriyor. Tek görevlik oturumda toplam 13 mesajın
yedisi kurulumdur; on iki göreve çıkıldığında kurulum yine **7 mesaj ve 109 belirteçte** kalır,
iş ise 60 mesaja ve 810 belirtece çıkar. Kurulum sabit bir bedeldir ve oturum uzadıkça payı
düşer; bir oturumu kısa tutmanın bedeli tam olarak budur.

Üçüncü ve dördüncü satırlar sürecin ömrünü sayıya çevirir. Süreç öldüğünde ne bir hata mesajı ne
bir bildirim üretilir; ölüm mesaj akışında görünmez. İstemci bunu ancak bir sonraki çağrıyı
gönderemediğinde anlar ve o çağrı da hiç tele çıkmadığı için sayıma girmez. Toparlanma ise
kurulumun **tamamını** yeniden ödetir: bir düşme mesajı 67'den 74'e, zarf belirtecini 919'dan
**1028'e**, gidiş-dönüşü 41'den 46'ya çıkarır — yani tam olarak bir kurulum kadar. Üç düşmede
belirteç **1246** olur; eklenen 327 belirteç, dört bedel zincirinin bedeline yakındır.

Tamamlanan görev dört satırda da düşmedi. Bu, toparlanmanın işi kurtardığı anlamına gelir ve
bedelin nereye yazılacağını da söyler: süreç düşmesi bu kurguda bir **doğruluk** sorunu değil, bir
**mesaj** sorunudur. İkinci koşumda görevler başka bir tohumla çekilir ve üç sayı da aynı kalır;
ölçü verinin değil sözleşmenin ve sürecin özelliğidir.

## Özet

- Yerel sunucu ayrı bir süreçtir: başlatılır, hazır olduğunu yanıt beklemeyen bir bildirim
  mesajıyla söyler ve oturumun ömrü onun ömrüyle sınırlıdır.
- İlk araç çağrısına kadar 7 mesaj ve 109 belirteç geçer: süreç başlatma 1 mesaj ve 10 belirteç,
  sunucu keşfi 6 mesaj ve 99 belirteç. Bildirim gidiş-dönüş eklemez.
- Üç araçlık zincir 3 istek, 3 yanıt, 80 belirteç ve 4 gidiş-dönüş tutar; iki yerel adım birer,
  bir uzak adım iki gidiş-dönüş sayar.
- Tek görevlik oturumda kurulum işten pahalıdır (7 mesaja karşı 6); on iki görevde kurulum yine
  7 mesajda kalırken iş 60 mesaja çıkar.
- Süreç ölümü ne hata ne mesaj üretir; yalnız sonraki çağrının gönderilememesiyle anlaşılır.
- Toparlanma kurulumun tamamını yeniden ödetir: bir düşme belirteci 919'dan 1028'e, üç düşme
  1246'ya çıkarır, tamamlanan görev on ikide kalır.

## Sonraki Adım

Bu üç derste sunucu yazıldı, istemci yazıldı ve ikisi arasındaki bağlantı bir süreç olarak kuruldu.
Bütün ölçümlerin ortak bir zemini vardı: sunucu **aynı makinedeydi**. Süreci başlatan, öldüğünü
fark eden ve yeniden kuran taraf ile sunucunun kendisi tek bir sınırın içinde duruyordu; kimin
kim olduğu hiç sorulmadı, çünkü sorulacak bir şey yoktu. Sunucu ağın ötesine geçtiğinde bağlantının
kendisi bir güven sorusu hâline gelir. Sonraki ders uzak bağlantıyı kurar ve yalnız onun eklediği
adımları sayar: kimlik adımı, yetki adımı ve gidiş-dönüş, yerel kurulumun sayılarıyla yan yana.
