---
title: 'Sunucu Gönderimli Olaylar'
source: 'https://academia.sh/tr/kurslar/uygulama-protokolleri/sunucu-gonderimli-olaylar'
course: 'Uygulama Katmanı Protokolleri'
language: tr
updated: '2026-08-17T18:07:02+00:00'
license: 'CC BY-SA 4.0'
---

# Sunucu Gönderimli Olaylar

Akışın HTTP kalmasının aracıya ne bıraktığı: baş iletinin taşıdığı beş karar, olay sayısı arttıkça karar noktasının seyrelmesi, bir kez alınan kararın gövdenin tamamına uygulanmasının doğurduğu yanlış ve tamponlayan bir aracının olayları ne kadar geciktirdiği.

Önceki ders tünelin bedelini saydı: yükseltmeden sonra aracı iki yüz kararın tamamını
kaybediyor, kırk alışverişin kırkı tur borcuna dönüşüyordu. Ama sunucunun istemciye
kendiliğinden veri göndermesi için bağlantının biçimini değiştirmek zorunlu değildir. HTTP
yanıtının gövdesinin tek seferde yazılması hiçbir yerde şart koşulmaz: gövde açık tutulup
üzerine parça parça yazılabilir.

**Sunucu gönderimli olaylar (Server-Sent Events, SSE)** bu seçeneği bir biçime bağlar. Tek
bir GET isteğine verilen tek bir yanıt açık tutulur ve sunucu ona sırayla olay yazar. Bu
dersin ölçüsü şudur: akış **HTTP kaldığı için** aracı iletiyi hâlâ okuyabilir — peki elinde
kaç karar kalır ve okuyabilmenin karşılığında ne öder?

## Akış Yanıtı

İstek olağandır. Yanıt da olağandır; onu ayıran tek şey **ortam türü (media type)** ve
gövdenin bitmemesidir.

```text
GET /akis/olcum HTTP/1.1
Host: istasyon.ornek
Accept: text/event-stream

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-store
Transfer-Encoding: chunked

event: olcum
id: 17
data: {"istasyon": "kuzey-yamac", "deger": 3}

: yorum satırı hiçbir olay üretmez

event: olcum
id: 18
data: {"istasyon": "kuzey-yamac", "deger": 5}
```

Gövde satır tabanlıdır: alan satırları bir olayı kurar, boş satır onu kapatır, iki nokta
ile başlayan satır yorumdur. Uzunluk önceden bilinemediği için gövde **parçalı aktarım
(chunked transfer)** ile ya da bağlantının kapanmasıyla sonlanır. Alan biçiminin ayrıntısı,
`id` alanına dayanan yeniden bağlanma ve sunucu tarafının bağlantı başına ödediği maliyet
**Önbellekleme, Kuyruklar ve Eşzamansız İşleme** kursunda ölçüldü. **Burada ölçülen,
aradaki aracının bu iletiden alabildiği karardır.**

## Karar Noktası

- **DG6.** Önceki derste bir bağlantı üzerinde taşınan kırk alışveriş, burada bir akışın
  gövdesinde taşınır. `olay`, tek bir akışın gövdesine yazılan alışveriş sayısıdır;
  `olay = 1` her alışverişin kendi isteğini açtığı istek–yanıt biçimidir.
- **DG7.** Aracı kararını akışın **baş iletisinden** alır. Gövdeye yazılan olaylar kendi
  istek satırını ve başlık alanlarını taşımaz; aracı için görünmezdirler.
- **DG8.** `kapsam yanlışı` sütunu ikinci bir okumadır: baş iletiden alınan karar
  gövdedeki **her olaya** uygulandığında kaç kararın yanlış olduğunu sayar.
- **DG9.** Son satır, iletinin hiçbir alanının okunamadığı tünel rejimidir; önceki dersin
  ölçümüyle karşılaştırma için buraya alınmıştır.

```python
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"]
KARARLAR = ("saklanabilir", "paylasilabilir", "taze", "yinelenebilir",
            "yonlendirilebilir")
ACIK = ("yontem", "yol", "konak", "ozel_imi", "dogrulayici")


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) -> 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 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"]}
    return {k: v for k, v in tam.items() if k in gorunur}


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_akis(olay: int, gorunur: tuple = ACIK) -> tuple:
    liste = alisverisler()
    nokta = dogru = yanlis = alinamayan = tur = bayt = kapsam = 0
    for i, a in enumerate(liste):
        m = ileti(liste[i - i % olay], gorunur)     # akışı açan iletinin alanları
        bastan, gercek = araci(m), kahin(a)
        kapsam += sum(bastan[k] != gercek[k] for k in bastan)
        verilen = bastan if i % olay == 0 else {}   # karar yalnız akış başında alınır
        dogru += sum(verilen[k] == gercek[k] for k in verilen)
        yanlis += sum(verilen[k] != gercek[k] for k in verilen)
        alinamayan += len(KARARLAR) - len(verilen)
        tur += 1 if len(verilen) < len(KARARLAR) else 0
        if i % olay == 0:
            nokta += 1
            bayt += sum(len(k) + len(str(v)) + 4 for k, v in m.items())
    return nokta, dogru, yanlis, alinamayan, tur, bayt, kapsam


bicim = "{:>5s} {:>6d} {:>6d} {:>7d} {:>11d} {:>4d} {:>6d} {:>14d}"
print(f"{'olay':>5s} {'nokta':>6s} {'doğru':>6s} {'yanlış':>7s} "
      f"{'alınamayan':>11s} {'tur':>4s} {'bayt':>6s} {'kapsam yanlışı':>14s}")
for olay in (1, 2, 4, 8, 20, 40):
    print(bicim.format(str(olay), *olc_akis(olay)))
print(bicim.format("-", *olc_akis(40, gorunur=())))

liste = alisverisler()
bas = araci(ileti(liste[0], ACIK))
print()
print("olay=40 kapsamında karar başına yanlış (40 olay üzerinden):")
for k in KARARLAR:
    y = sum(bas[k] != kahin(a)[k] for a in liste)
    print(f"  {k:<18s} baş iletideki değer {str(bas[k]):<5s} yanlış {y:2d}/40")
```

```
 olay  nokta  doğru  yanlış  alınamayan  tur   bayt kapsam yanlışı
    1     40    195       5           0    0   3524              5
    2     20     97       3         100   20   1747             37
    4     10     47       3         150   30    879             45
    8      5     23       2         175   35    436             57
   20      2      9       1         190   38    179             71
   40      1      4       1         195   39     87             73
    -      1      0       0         200   40      0              0

olay=40 kapsamında karar başına yanlış (40 olay üzerinden):
  saklanabilir       baş iletideki değer False yanlış 13/40
  paylasilabilir     baş iletideki değer True  yanlış 17/40
  taze               baş iletideki değer True  yanlış 12/40
  yinelenebilir      baş iletideki değer False yanlış 31/40
  yonlendirilebilir  baş iletideki değer True  yanlış  0/40
```

İlk satır istek–yanıt biçimidir ve kursun ölçtüğü açık rejimin ta kendisidir: 195 doğru,
5 yanlış, hiç alınamayan karar yok, hiç tur borcu yok, 3524 bayt. Son satır önceki dersin
tünel rejimidir: 0 karar, 200 alınamayan, 40 tur borcu.

Aradaki satırlar akışın ne yaptığını gösterir. Kırk olay tek bir gövdeye yazıldığında aracı
**bir** karar noktasında kalır ve elinde **beş** karar bulunur. Bu, tünelin sıfırından beş
karar fazladır ve fark tam olarak şuradan gelir: akışı açan yanıt **okunabilir bir HTTP
yanıtıdır.** Önceki derste 101 yanıtı kişiye özel imi de doğrulayıcı da taşımadığı için
sıfır karar veriyordu; burada yanıt olağan bir 200'dür ve beş kararın beşini de besler.

Baytın düşüşü de aynı yerden gelir. 3524 bayttan 87 bayta inen şey, kırk iletinin başlık
alanlarının otuz dokuzunun hiç gönderilmemesidir. Alan gitmiş, karar da gitmiştir; bu,
önceki dersin sonucuyla aynı yöndedir. **Bayt ile karar birlikte düşer, çünkü ikisini de
taşıyan şey alandır.**

## Kararın Kapsamı

Karar noktasının seyrelmesi kayıpların tamamı değildir. Bir aracı, akışın başında aldığı
kararı unutmaz — onu **gövdenin tamamına** uygular. Yanıtı saklanabilir saydıysa gövdenin
tümünü saklar; taze saydıysa gövdenin tümünü taze sayar.

`kapsam yanlışı` sütunu bunu ölçer. `olay = 1` iken baş ileti ile olay aynı şeydir ve
sütun beş yanlışı verir. `olay = 40` iken tek bir karar kümesi kırk olaya uygulanır ve
iki yüz kararın **73'ü** yanlış çıkar. Karar noktası birden kırka çıkmamıştır; **kararın
kapsamı** bire kırktan yayılmıştır.

Alt döküm 73'ün nereden geldiğini söyler. `yonlendirilebilir` hiç yanılmaz, çünkü değeri
her alışverişte aynıdır; kapsamın genişlemesi **değişmeyen** bir kararı bozmaz.
`yinelenebilir` ise 31 kez yanılır: baş ileti bir POST'tur ve kararı `False` çıkmıştır, oysa
gövdedeki olayların çoğu güvenli yöntemlere aittir. Kalan üçü — `saklanabilir` 13,
`paylasilabilir` 17, `taze` 12 — kişiye özellik ve bayatlığın olaydan olaya değişmesinden
gelir. Kural şudur: **kapsamın genişlemesi, yalnız alışverişten alışverişe değişen
kararları bozar.**

Bu, akışın en sessiz maliyetidir. Karar noktasında ölçüldüğünde aracının yalnız **bir**
yanlışı vardır ve bu, açık rejimin beş yanlışından azdır. Aynı akış kapsamında ölçüldüğünde
yanlış sayısı beşten 73'e çıkar. Kümenin çözünürlüğü 1/200 = 0,0050 olduğuna göre bu fark
ölçülebilir bandın çok üstündedir ve yorum farkından değil, **kararın ne kadar süre geçerli
sayıldığından** gelir. Akış yanıtının önbelleklenmeye kapatılmasının nedeni budur.

## Yeniden Bağlanma Bir Karar Noktasıdır

Tablodaki `olay` sütunu tek bir soruyu daha yanıtlar. Bir akış hiçbir zaman sonsuza kadar
ayakta kalmaz; bağlantı kopar, istemci yeniden bağlanır. Yeniden bağlanma yeni bir istek,
yeni bir istek ise **yeni bir karar noktasıdır.** Yirmi olayda bir kopan bir akış tablonun
`olay = 20` satırıdır: iki karar noktası, on karar. Sekiz olayda bir kopan akış beş nokta ve
yirmi beş karar verir. Aracının gördüğü şey, akışın ne kadar kararlı olduğuyla ters
orantılıdır.

Bunun bir sonucu yönlendirmedir. `yonlendirilebilir` kararı akışın başında bir kez alınır
ve akış boyunca **dondurulur**. İstek–yanıt biçiminde aracı kırk alışverişin her birini
ayrı ayrı yönlendirebilir; bir üst kaynak yanıt vermediğinde sonraki isteği başka bir yere
gönderir. Tek bir akışta bu esneklik yoktur: seçim bir kez yapılmıştır ve değiştirmenin tek
yolu akışı kesmektir. Kesmek de yeni bir karar noktası doğurur, yani aracının yönlendirmeyi
düzeltmesi ancak istemcinin yeniden bağlanmasıyla mümkün olur.

Kopmanın ucuz olmasını sağlayan alan — istemcinin en son gördüğü olay kimliğini yeni isteğe
iliştirmesi — bu tabloda hiçbir karar üretmez. Aracı o alanı okur ama ondan çıkaracağı bir
şey yoktur; alan uçlar arasındaki bir sözleşmedir. Bu, kursun dört numaralı okumasının bir
başka örneğidir: **bir alanın var olması, aracının ondan karar çıkarabildiği anlamına
gelmez.**

## Tamponlama

Aracı iletiyi okuyabildiği için gövdeyi de görür, ve gördüğü şey üzerinde bir seçim yapar:
baytı hemen mi iletsin, yoksa biriktirip toplu mu göndersin. Biriktirmek olağan bir
verimlilik kuralıdır; bitmeyen bir gövdede ise olayları geciktirir.

- **DG10.** Aracı, tamponu eşiğe ulaşmadan gövdeden hiçbir bayt iletmez. Eşik 0 ise
  tamponlama yoktur. Olay metinleri belirtimin satır biçimiyle üretilir, değerler kurgudur.

```python
def olay_metni(no: int, deger: int) -> str:
    """Belirtimin satır biçimi: alan satırları ve olayı kapatan boş satır."""
    return (f"event: olcum\nid: {no}\n"
            f'data: {{"istasyon": "kuzey-yamac", "deger": {deger}}}\n\n')


OLAYLAR = [olay_metni(i + 1, i * 3 % 97) for i in range(40)]


def tamponla(esik: int) -> tuple:
    tampon, grup, bekleme = 0, [], []
    for i, m in enumerate(OLAYLAR):
        tampon += len(m)
        grup.append(i)
        if tampon >= esik:
            bekleme.extend(i - j for j in grup)   # her olayın kaç olay beklediği
            tampon, grup = 0, []
    ortalama = sum(bekleme) / len(bekleme) if bekleme else 0.0
    return len(bekleme), max(bekleme, default=0), ortalama, len(grup)


print(f"olay sayısı {len(OLAYLAR)}, olay boyu "
      f"{min(len(m) for m in OLAYLAR)}-{max(len(m) for m in OLAYLAR)} bayt, "
      f"gövde {sum(len(m) for m in OLAYLAR)} bayt")
print()
print(f"{'eşik':>6s} {'iletilen':>9s} {'en çok bekleme':>15s} "
      f"{'ortalama bekleme':>17s} {'sonda tutulan':>14s}")
for esik in (0, 128, 256, 1024, 4096):
    iletilen, en_cok, ortalama, tutulan = tamponla(esik)
    ec = str(en_cok) if iletilen else "-"
    ort = f"{ortalama:.2f}" if iletilen else "-"
    print(f"{esik:6d} {iletilen:9d} {ec:>15s} {ort:>17s} {tutulan:14d}")
```

```
olay sayısı 40, olay boyu 66-68 bayt, gövde 2704 bayt

  eşik  iletilen  en çok bekleme  ortalama bekleme  sonda tutulan
     0        40               0              0.00              0
   128        40               1              0.50              0
   256        40               3              1.50              0
  1024        32              15              7.50              8
  4096         0               -                 -             40
```

İki bakışla okunur. İlk üç satırda gecikme eşikle orantılı büyür: 256 baytlık bir tampon
olayları ortalama 1,5 olay geciktirir. Son satır ise farklı bir şeydir. Akışın kırk olayda
ürettiği toplam gövde 2704 bayttır ve 4096 baytlık bir eşik bu gövdenin tamamından
büyüktür; aracı hiçbir baytı iletmez ve akış, kapanana kadar istemci için **hiç var
olmamıştır.**

Kritik olan şudur: aracı yanlış bir şey yapmıyor. Bir yanıtı biriktirmek, bitmiş bir gövde
için doğru davranıştır. Aracının bilmediği şey gövdenin bitmeyeceğidir ve bunu ona söyleyen
tek alan **ortam türüdür**. `text/event-stream` değerini tanımayan bir aracının elinde
başka hiçbir im yoktur: gövde uzunluğu bildirilmemiştir, yöntem GET'tir, durum kodu 200'dür
ve bunların hiçbiri "bu gövde bitmeyecek" demez. Sunucu tarafının kalp atışı satırıyla
aldığı önlem, aynı boşluğun öbür uçtan kapatılmasıdır ve o kurs içinde ölçülmüştü.

## Tek Yön

Akış tek yönlüdür: sunucudan istemciye. İstemcinin sunucuya söyleyeceği bir şey olduğunda
akışa yazamaz, olağan bir istek açar. Bu, ölçüm tablosunda kayıp gibi görünmeyen bir
ayrıntıdır ama sonucu doğrudandır: **istemciden gelen her ileti yeniden bir karar
noktasıdır.** Akış tarafında karar noktası bire inmiştir; istemcinin sunucuya yazdığı her
istek ise ölçüm tablosunun ilk satırındaki gibi okunabilir bir alışveriştir ve kendi karar
noktasını geri getirir.

Tünelde bu bile yoktur; oradaki her iki yönlü ileti aynı çerçeve biçimindedir ve hiçbiri
karar üretmez. Aradaki fark, seçimin ne üzerinden yapıldığını da gösterir: iki yön gerçekten
gerekliyse tünel, gereken şey yalnız sunucu akışıysa SSE. Yönün bedeli karar cinsinden
ölçülebilir.

## Özet

- Sunucu gönderimli olaylar HTTP'nin içinde kalır: istek olağan bir GET, yanıt olağan bir
  200'dür ve gövde açık tutulup üzerine olay yazılır.
- Kırk olay tek bir akışta taşındığında aracının karar noktası bire iner ve elinde beş
  karar kalır; tünel rejiminde bu sayı sıfırdır ve fark, akışı açan yanıtın okunabilir
  olmasından gelir.
- Baş iletiden alınan karar gövdenin tamamına uygulanır; karar noktasında ölçülen yanlış
  sayısı 1 iken kapsamda ölçülen yanlış sayısı iki yüz kararın 73'üdür.
- Bayt 3524'ten 87'ye inerken karar da 200'den 5'e iner; ikisini de taşıyan şey alandır.
- Tamponlayan bir aracı 256 baytlık eşikte olayları ortalama 1,5 olay geciktirir; 2704
  baytlık gövdeye karşılık 4096 baytlık bir eşikte hiçbir olay iletilmez ve gövdenin
  bitmeyeceğini söyleyen tek alan ortam türüdür.

## Sonraki Adım

Akış da tünel de bağlantıyı **açık tutarak** çalışıyor: biri gövdeyi bitirmiyor, öbürü
protokolü değiştiriyor. İkisi de sunucunun elini serbest bırakmak için bağlantının süresini
uzatıyor. Peki hiçbirini yapmadan, protokole tek bir yeni alan bile eklemeden, yalnız daha
sık sorarak nereye kadar gidilir? Sonraki ders bunu ölçer: kısa yoklama, uzun yoklama ve
sunucu akışı aynı olay kümesi üzerinde yan yana konur ve bölen olay değil, **karar**
olur.
