<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://sonsuzus.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sonsuzus.github.io/" rel="alternate" type="text/html" /><updated>2026-07-14T15:41:17+00:00</updated><id>https://sonsuzus.github.io/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">C ile Donanım İletişimi: Eski Disklerden Adaptörlere Sürücü Mantığı</title><link href="https://sonsuzus.github.io/posts/c-ile-donanim-iletisimi-eski-disklerden-adaptorlere-surucu-mantigi/" rel="alternate" type="text/html" title="C ile Donanım İletişimi: Eski Disklerden Adaptörlere Sürücü Mantığı" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-donanim-iletisimi-eski-disklerden-adaptorlere-surucu-mantigi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-donanim-iletisimi-eski-disklerden-adaptorlere-surucu-mantigi/"><![CDATA[<p>Eski bir IDE disk, USB-SATA dönüştürücü ya da seri port adaptörü elinize geçtiğinde ilk soru genelde şudur: “Bunu işletim sistemiyle nasıl konuştururum?” C dili burada hâlâ sahnenin başrol oyuncusudur; çünkü donanıma yakın, bellek düzenini tahmin edilebilir kılan ve kesme, DMA, I/O portu gibi düşük seviye kavramları açıkça modelleyebilen bir araçtır.
``
Donanım iletişimini sürücü seviyesinde düşünürken üç katmanı ayırmak gerekir: fiziksel aygıt, denetleyici protokolü ve işletim sistemi arayüzü. Örneğin eski bir ATA disk doğrudan “dosya” bilmez; sektör okur, sektör yazar. Dosya sistemi ise bu ham blokların üzerine kurulan daha üst seviye bir soyutlamadır. Sürücü algoritmanızın görevi, işletim sisteminden gelen “şu blokları oku” isteğini aygıtın anlayacağı komutlara çevirmektir.</p>

<p>Teorik olarak blok tabanlı aygıtlarda en küçük adreslenebilir birim genellikle sektördür. Klasik disklerde sektör boyutu çoğunlukla 512 bayt, yeni disklerde ise 4096 bayt olabilir. Bir okuma işleminin yaklaşık maliyeti şu şekilde düşünülebilir:</p>

\[T_{okuma} = T_{arama} + T_{gecikme} + \frac{B}{R}\]

<p>Burada $B$ okunan bayt miktarı, $R$ aktarım hızı, $T_{arama}$ mekanik kafanın konumlanma süresi, $T_{gecikme}$ ise dönüş gecikmesidir. SSD ve USB adaptörlerde mekanik süreler yoktur ama komut kuyruğu, veri yolu gecikmesi ve köprü yongasının davranışı hâlâ önemlidir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Kullanım Alanı</th>
      <th>Avantaj</th>
      <th>Risk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Port I/O</td>
      <td>Eski x86 ATA, seri port</td>
      <td>Basit ve doğrudan</td>
      <td>Mimariye bağımlı</td>
    </tr>
    <tr>
      <td>MMIO</td>
      <td>PCI/PCIe aygıtlar</td>
      <td>Bellek gibi erişim</td>
      <td>Yanlış adres sistemi kilitleyebilir</td>
    </tr>
    <tr>
      <td>DMA</td>
      <td>Yüksek hızlı disk, ağ kartı</td>
      <td>CPU yükü az</td>
      <td>Bellek eşleme hataları tehlikeli</td>
    </tr>
    <tr>
      <td>USB sınıf sürücüsü</td>
      <td>Harici adaptörler</td>
      <td>Standart protokoller</td>
      <td>Köprü yongası farklı davranabilir</td>
    </tr>
  </tbody>
</table>

<p>C tarafında en temel fikir, donanım kayıtlarını temsil eden kesin boyutlu veri tipleri kullanmaktır. <code class="language-plaintext highlighter-rouge">uint8_t</code>, <code class="language-plaintext highlighter-rouge">uint16_t</code> ve <code class="language-plaintext highlighter-rouge">uint32_t</code> bu yüzden önemlidir. Ayrıca derleyicinin optimizasyon sırasında donanım erişimini “gereksiz” sanıp silmemesi için <code class="language-plaintext highlighter-rouge">volatile</code> kullanılır.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdint.h&gt;</span><span class="cp">
</span>
<span class="cp">#define ATA_DATA       0x1F0
#define ATA_SECTOR_CNT 0x1F2
#define ATA_LBA_LOW    0x1F3
#define ATA_COMMAND    0x1F7
</span>
<span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">outb</span><span class="p">(</span><span class="kt">uint16_t</span> <span class="n">port</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">__asm__</span> <span class="k">volatile</span> <span class="p">(</span><span class="s">"outb %0, %1"</span> <span class="o">:</span> <span class="o">:</span> <span class="s">"a"</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="s">"Nd"</span><span class="p">(</span><span class="n">port</span><span class="p">));</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kr">inline</span> <span class="kt">uint8_t</span> <span class="nf">inb</span><span class="p">(</span><span class="kt">uint16_t</span> <span class="n">port</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">value</span><span class="p">;</span>
    <span class="n">__asm__</span> <span class="k">volatile</span> <span class="p">(</span><span class="s">"inb %1, %0"</span> <span class="o">:</span> <span class="s">"=a"</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">:</span> <span class="s">"Nd"</span><span class="p">(</span><span class="n">port</span><span class="p">));</span>
    <span class="k">return</span> <span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu örnekte x86 üzerinde I/O portlarına erişen küçük yardımcı fonksiyonlar var. <code class="language-plaintext highlighter-rouge">outb</code> donanıma komut veya parametre gönderir, <code class="language-plaintext highlighter-rouge">inb</code> ise durum bayrağı okur. Gerçek bir çekirdek sürücüsünde bunlar doğrudan kullanıcı programından çağrılamaz; ayrıcalıklı kip gerekir. Linux’ta bu iş çekirdek modülü, Windows’ta ise WDM/KMDF sürücüsü üzerinden yapılır.</p>

<p>Bir sürücü algoritmasının kalbi genellikle durum makinesidir. Aygıta komut verilir, aygıt meşgul olur, sonra hazır bayrağı beklenir. Basitleştirilmiş akış şöyledir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">disk_state</span> <span class="p">{</span>
    <span class="n">DISK_IDLE</span><span class="p">,</span>
    <span class="n">DISK_SEND_CMD</span><span class="p">,</span>
    <span class="n">DISK_WAIT_READY</span><span class="p">,</span>
    <span class="n">DISK_TRANSFER</span><span class="p">,</span>
    <span class="n">DISK_ERROR</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">wait_ready</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">uint8_t</span> <span class="n">status</span> <span class="o">=</span> <span class="n">inb</span><span class="p">(</span><span class="n">ATA_COMMAND</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">((</span><span class="n">status</span> <span class="o">&amp;</span> <span class="mh">0x80</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">status</span> <span class="o">&amp;</span> <span class="mh">0x08</span><span class="p">))</span>
            <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">0x80</code> meşgul bayrağını, <code class="language-plaintext highlighter-rouge">0x08</code> veri hazır bayrağını temsil eder. Döngü sonsuza kadar beklemek yerine zaman aşımı uygular; çünkü donanım dünyasında “cevap gelmedi” de geçerli bir cevaptır. Sağlam sürücü yazmanın sırrı, mutlu yoldan çok hata yollarını ciddiye almaktır.</p>

<p>Harici adaptörlerde tablo biraz değişir. USB-SATA köprüleri çoğunlukla Mass Storage Class ya da UASP kullanır. Siz doğrudan ATA portuna yazmazsınız; SCSI benzeri komut paketleri gönderirsiniz. Yani algoritma yine blok okuma/yazma yapar ama alttaki taşıma protokolü farklıdır. Bu yüzden iyi tasarımda “blok aygıt arayüzü” ile “taşıma katmanı” ayrılır.</p>

<p>Son olarak güvenlik notu: Gerçek disklere deneme sürücüsüyle yazmak veri kaybına yol açabilir. Önce QEMU, Bochs, loop device veya sahte blok aygıtlarıyla test yapmak en sağlıklı yoldur. C ile donanım konuşmak, biraz arkeoloji biraz da elektrikli ejderha terbiyeciliğidir: protokolü okur, bayrakları izler, zaman aşımını koyar ve asla donanıma körü körüne güvenmezsiniz.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="C" /><category term="donanım" /><category term="sürücü-geliştirme" /><summary type="html"><![CDATA[Eski bir IDE disk, USB-SATA dönüştürücü ya da seri port adaptörü elinize geçtiğinde ilk soru genelde şudur: “Bunu işletim sistemiyle nasıl konuştururum?” C dili burada hâlâ sahnenin başrol oyuncusudur; çünkü donanıma yakın, bellek düzenini tahmin edilebilir kılan ve kesme, DMA, I/O portu gibi düşük seviye kavramları açıkça modelleyebilen bir araçtır.]]></summary></entry><entry><title type="html">C++ ile Kriptografik Şifreleme: Matematiği Kodla Kilide Çevirmek</title><link href="https://sonsuzus.github.io/posts/c-ile-kriptografik-sifreleme-matematigi-kodla-kilide-cevirmek/" rel="alternate" type="text/html" title="C++ ile Kriptografik Şifreleme: Matematiği Kodla Kilide Çevirmek" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-kriptografik-sifreleme-matematigi-kodla-kilide-cevirmek</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-kriptografik-sifreleme-matematigi-kodla-kilide-cevirmek/"><![CDATA[<p>Kriptografi, bilgisayar biliminin en havalı sihirbazlık numaralarından biridir: okunabilir bir mesajı, matematiksel işlemlerle anlamsız görünen bir yığına dönüştürür; sonra doğru anahtarla tekrar eski haline getirir. C++ ise belleğe yakın çalışması, hızlı aritmetik işlemleri ve sistem seviyesinde kontrol sunması sayesinde bu algoritmaları anlamak için harika bir laboratuvardır.
``</p>
<h2 id="şifreleme-fikri-kilit-anahtar-ve-dönüşüm">Şifreleme fikri: kilit, anahtar ve dönüşüm</h2>

<p>Bir şifreleme algoritmasını kabaca şu fonksiyon gibi düşünebiliriz: $C = E(M, K)$. Burada $M$ açık mesaj, $K$ anahtar, $E$ şifreleme fonksiyonu ve $C$ şifreli metindir. Çözme tarafında ise $M = D(C, K)$ ya da asimetrik sistemlerde farklı bir anahtar kullanılarak $M = D(C, K_{private})$ elde edilir.</p>

<p>Temel ayrım şudur:</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th style="text-align: right">Kullanılan anahtar</th>
      <th style="text-align: right">Hız</th>
      <th>Tipik kullanım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Simetrik şifreleme</td>
      <td style="text-align: right">Aynı gizli anahtar</td>
      <td style="text-align: right">Çok hızlı</td>
      <td>Dosya, disk, veri akışı</td>
    </tr>
    <tr>
      <td>Asimetrik şifreleme</td>
      <td style="text-align: right">Açık + özel anahtar</td>
      <td style="text-align: right">Daha yavaş</td>
      <td>Anahtar değişimi, imza</td>
    </tr>
    <tr>
      <td>Hash</td>
      <td style="text-align: right">Anahtar yok / opsiyonel</td>
      <td style="text-align: right">Hızlı</td>
      <td>Bütünlük kontrolü, parola özeti</td>
    </tr>
  </tbody>
</table>

<p>Bu yazıda eğitim amacıyla küçük bir RSA benzeri yapı kuracağız. Gerçek dünyada kendi kriptonuzu üretip canlı sistemde kullanmak genellikle kötü fikirdir; AES, ChaCha20, RSA-OAEP gibi incelenmiş standartlar ve OpenSSL/libsodium gibi kütüphaneler tercih edilmelidir. Ama mantığı kodlamak öğrenmenin en iyi yollarından biridir.</p>

<h2 id="rsanın-matematiksel-kalbi">RSA’nın matematiksel kalbi</h2>

<p>RSA, büyük asal sayıların çarpanlara ayrılmasının zorluğuna dayanır. İki asal seçeriz: $p$ ve $q$. Sonra $n = p \times q$ hesaplanır. Bu $n$, hem açık hem özel anahtar tarafında kullanılır.</p>

<p>Euler phi değeri: $\varphi(n) = (p-1)(q-1)$.</p>

<p>Açık üs $e$, $\varphi(n)$ ile aralarında asal seçilir. Özel üs $d$ ise şu koşulu sağlar: $d \times e \equiv 1 \pmod{\varphi(n)}$.</p>

<p>Şifreleme: $C = M^e \mod n$<br />
Çözme: $M = C^d \mod n$</p>

<p>Buradaki sihir, modüler aritmetiktedir. Sayılar devasa büyümeden üs alma yapmak için “hızlı üs alma” tekniği kullanılır.</p>

<h2 id="c-ile-mini-rsa-deneyi">C++ ile mini RSA deneyi</h2>

<p>Aşağıdaki kod güvenli değildir; çünkü çok küçük asal sayılar kullanır. Amacı, RSA mantığını elle tutulur hale getirmektir.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdint&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">uint64_t</span> <span class="nf">modPow</span><span class="p">(</span><span class="kt">uint64_t</span> <span class="n">base</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">exp</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">mod</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint64_t</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">base</span> <span class="o">%=</span> <span class="n">mod</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">exp</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">exp</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="n">result</span> <span class="o">*</span> <span class="n">base</span><span class="p">)</span> <span class="o">%</span> <span class="n">mod</span><span class="p">;</span>
        <span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="n">base</span> <span class="o">*</span> <span class="n">base</span><span class="p">)</span> <span class="o">%</span> <span class="n">mod</span><span class="p">;</span>
        <span class="n">exp</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int64_t</span> <span class="nf">egcd</span><span class="p">(</span><span class="kt">int64_t</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="o">&amp;</span><span class="n">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">b</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">return</span> <span class="n">a</span><span class="p">;</span> <span class="p">}</span>
    <span class="kt">int64_t</span> <span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">;</span>
    <span class="kt">int64_t</span> <span class="n">g</span> <span class="o">=</span> <span class="n">egcd</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">%</span> <span class="n">b</span><span class="p">,</span> <span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">);</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">y1</span><span class="p">;</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">x1</span> <span class="o">-</span> <span class="p">(</span><span class="n">a</span> <span class="o">/</span> <span class="n">b</span><span class="p">)</span> <span class="o">*</span> <span class="n">y1</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">g</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">uint64_t</span> <span class="nf">modInverse</span><span class="p">(</span><span class="kt">uint64_t</span> <span class="n">e</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">phi</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int64_t</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">;</span>
    <span class="n">egcd</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">phi</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">x</span> <span class="o">%</span> <span class="p">(</span><span class="kt">int64_t</span><span class="p">)</span><span class="n">phi</span> <span class="o">+</span> <span class="n">phi</span><span class="p">)</span> <span class="o">%</span> <span class="n">phi</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">uint64_t</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">61</span><span class="p">,</span> <span class="n">q</span> <span class="o">=</span> <span class="mi">53</span><span class="p">;</span>
    <span class="kt">uint64_t</span> <span class="n">n</span> <span class="o">=</span> <span class="n">p</span> <span class="o">*</span> <span class="n">q</span><span class="p">;</span>
    <span class="kt">uint64_t</span> <span class="n">phi</span> <span class="o">=</span> <span class="p">(</span><span class="n">p</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
    <span class="kt">uint64_t</span> <span class="n">e</span> <span class="o">=</span> <span class="mi">17</span><span class="p">;</span>
    <span class="kt">uint64_t</span> <span class="n">d</span> <span class="o">=</span> <span class="n">modInverse</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">phi</span><span class="p">);</span>

    <span class="kt">uint64_t</span> <span class="n">message</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
    <span class="kt">uint64_t</span> <span class="n">encrypted</span> <span class="o">=</span> <span class="n">modPow</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
    <span class="kt">uint64_t</span> <span class="n">decrypted</span> <span class="o">=</span> <span class="n">modPow</span><span class="p">(</span><span class="n">encrypted</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>

    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Acik anahtar (e,n): ("</span> <span class="o">&lt;&lt;</span> <span class="n">e</span> <span class="o">&lt;&lt;</span> <span class="s">","</span> <span class="o">&lt;&lt;</span> <span class="n">n</span> <span class="o">&lt;&lt;</span> <span class="s">")</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Ozel anahtar d: "</span> <span class="o">&lt;&lt;</span> <span class="n">d</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Mesaj: "</span> <span class="o">&lt;&lt;</span> <span class="n">message</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Sifreli: "</span> <span class="o">&lt;&lt;</span> <span class="n">encrypted</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Cozulen: "</span> <span class="o">&lt;&lt;</span> <span class="n">decrypted</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">modPow</code> fonksiyonu, $M^e$ gibi astronomik büyüyebilecek ifadeleri güvenli şekilde mod içinde tutar. <code class="language-plaintext highlighter-rouge">egcd</code> yani genişletilmiş Öklid algoritması ise modüler ters bulur; RSA’daki özel anahtarın matematiksel üretim noktası burasıdır.</p>

<h2 id="neden-gerçek-sistemlerde-daha-fazlası-gerekir">Neden gerçek sistemlerde daha fazlası gerekir?</h2>

<p>Oyuncak RSA sadece iskeleti gösterir. Gerçek kriptografide asal üretimi, rastgelelik, dolgu şemaları ve yan kanal saldırılarına dayanıklılık kritik önemdedir.</p>

<table>
  <thead>
    <tr>
      <th>Konu</th>
      <th>Oyuncak örnek</th>
      <th>Gerçek dünya beklentisi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Asal sayılar</td>
      <td>61 ve 53</td>
      <td>2048+ bit güvenli asal</td>
    </tr>
    <tr>
      <td>Rastgelelik</td>
      <td>Sabit değerler</td>
      <td>Kriptografik RNG</td>
    </tr>
    <tr>
      <td>Dolgu</td>
      <td>Yok</td>
      <td>OAEP, PSS gibi standartlar</td>
    </tr>
    <tr>
      <td>Veri boyutu</td>
      <td>Küçük sayı</td>
      <td>Bloklama / hibrit şifreleme</td>
    </tr>
  </tbody>
</table>

<p>Pratikte RSA genellikle tüm dosyayı şifrelemek için değil, AES anahtarını güvenli taşımak için kullanılır. Buna hibrit şifreleme denir: hızlı simetrik algoritma veriyi şifreler, asimetrik algoritma ise anahtarı korur.</p>

<p>Sonuç olarak C++ ile kriptografi yazmak, matematik ve sistem programlamayı aynı masaya oturtur. Kendi mini aracınızı geliştirmek size $\mod$, asal sayılar ve anahtar mantığını öğretir; ancak üretimde güvenlik için test edilmiş kütüphanelere güvenmek en akıllıca hamledir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="C++" /><category term="Kriptografi" /><category term="RSA" /><category term="Veri Güvenliği" /><summary type="html"><![CDATA[Kriptografi, bilgisayar biliminin en havalı sihirbazlık numaralarından biridir: okunabilir bir mesajı, matematiksel işlemlerle anlamsız görünen bir yığına dönüştürür; sonra doğru anahtarla tekrar eski haline getirir. C++ ise belleğe yakın çalışması, hızlı aritmetik işlemleri ve sistem seviyesinde kontrol sunması sayesinde bu algoritmaları anlamak için harika bir laboratuvardır.]]></summary></entry><entry><title type="html">Go ile Ağ Tarayıcıları Yazmak: Hızlı ve Eşzamanlı Web Scraping</title><link href="https://sonsuzus.github.io/posts/go-ile-ag-tarayicilari-yazmak-hizli-ve-eszamanli-web-scraping/" rel="alternate" type="text/html" title="Go ile Ağ Tarayıcıları Yazmak: Hızlı ve Eşzamanlı Web Scraping" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/go-ile-ag-tarayicilari-yazmak-hizli-ve-eszamanli-web-scraping</id><content type="html" xml:base="https://sonsuzus.github.io/posts/go-ile-ag-tarayicilari-yazmak-hizli-ve-eszamanli-web-scraping/"><![CDATA[<p>İnternetteki veriler dağınık bir kütüphane gibidir: ürün fiyatları bir rafta, haber başlıkları başka rafta, açık veri tabloları ise bodrumda durur. Go ile yazılan bir web scraper, bu kütüphanede patenle gezen disiplinli bir arşivciye benzer. Hızlı HTTP istemcisi, goroutine yapısı ve channel mantığı sayesinde binlerce sayfayı kısa sürede ziyaret edip veriyi indeksleyebiliriz.
``
Web scraping temelde üç aşamadan oluşur: sayfayı indir, içeriği ayrıştır, anlamlı veriyi kaydet. Basit görünür ama işin teorik tarafında ağ gecikmesi, eşzamanlılık, hata toleransı ve etik sınırlar vardır. Bir isteğin toplam süresi yaklaşık olarak şöyle düşünülebilir: $T = T_{dns} + T_{tcp} + T_{tls} + T_{server} + T_{download}$. Tek tek çalışan bir tarayıcıda toplam süre $T_{seq} = n \times T$ olur. Eşzamanlı çalışan bir sistemde ise ideal durumda $T_{par} \approx \frac{n \times T}{w}$; burada $w$ worker sayısıdır. Elbette gerçek dünyada bant genişliği, hedef sunucu limitleri ve CPU bu denkleme biraz mizah katar.</p>

<p>Go bu iş için çok uygundur çünkü goroutine’ler hafiftir. Her URL için dev bir işletim sistemi thread’i açmak yerine, Go runtime binlerce işi verimli biçimde planlar. Channel’lar ise URL kuyruğu, sonuç akışı ve hata bildirimleri için temiz bir iletişim modeli sağlar.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
      <th>Uygun Senaryo</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sıralı istek</td>
      <td>Basit, hata ayıklaması kolay</td>
      <td>Çok yavaş</td>
      <td>10-20 sayfalık küçük işler</td>
    </tr>
    <tr>
      <td>Sınırsız goroutine</td>
      <td>İlk bakışta çok hızlı</td>
      <td>Sunucuyu boğabilir, rate limit yer</td>
      <td>Kontrollü olmayan deneyler, önerilmez</td>
    </tr>
    <tr>
      <td>Worker pool</td>
      <td>Dengeli, yönetilebilir</td>
      <td>Biraz daha fazla kod</td>
      <td>Gerçek projeler</td>
    </tr>
    <tr>
      <td>Kuyruk + retry</td>
      <td>Dayanıklı</td>
      <td>Mimari karmaşıklık artar</td>
      <td>Büyük ölçekli indeksleme</td>
    </tr>
  </tbody>
</table>

<p>Aşağıdaki örnekte kontrollü bir worker pool kuruyoruz. Amaç, URL listesini channel üzerinden worker’lara dağıtmak ve her sayfanın HTML uzunluğunu örnek olarak toplamaktır. Gerçek projede burada başlık, meta açıklama, ürün fiyatı veya linkler ayrıştırılabilir.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"io"</span>
    <span class="s">"net/http"</span>
    <span class="s">"sync"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Result</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">URL</span>    <span class="kt">string</span>
    <span class="n">Length</span> <span class="kt">int</span>
    <span class="n">Err</span>    <span class="kt">error</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">fetch</span><span class="p">(</span><span class="n">client</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Client</span><span class="p">,</span> <span class="n">url</span> <span class="kt">string</span><span class="p">)</span> <span class="n">Result</span> <span class="p">{</span>
    <span class="n">resp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">Result</span><span class="p">{</span><span class="n">URL</span><span class="o">:</span> <span class="n">url</span><span class="p">,</span> <span class="n">Err</span><span class="o">:</span> <span class="n">err</span><span class="p">}</span>
    <span class="p">}</span>
    <span class="k">defer</span> <span class="n">resp</span><span class="o">.</span><span class="n">Body</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>

    <span class="n">body</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">io</span><span class="o">.</span><span class="n">ReadAll</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">Body</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">Result</span><span class="p">{</span><span class="n">URL</span><span class="o">:</span> <span class="n">url</span><span class="p">,</span> <span class="n">Err</span><span class="o">:</span> <span class="n">err</span><span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">Result</span><span class="p">{</span><span class="n">URL</span><span class="o">:</span> <span class="n">url</span><span class="p">,</span> <span class="n">Length</span><span class="o">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">body</span><span class="p">)}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">worker</span><span class="p">(</span><span class="n">id</span> <span class="kt">int</span><span class="p">,</span> <span class="n">client</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Client</span><span class="p">,</span> <span class="n">jobs</span> <span class="o">&lt;-</span><span class="k">chan</span> <span class="kt">string</span><span class="p">,</span> <span class="n">results</span> <span class="k">chan</span><span class="o">&lt;-</span> <span class="n">Result</span><span class="p">,</span> <span class="n">wg</span> <span class="o">*</span><span class="n">sync</span><span class="o">.</span><span class="n">WaitGroup</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">defer</span> <span class="n">wg</span><span class="o">.</span><span class="n">Done</span><span class="p">()</span>
    <span class="k">for</span> <span class="n">url</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">jobs</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Worker"</span><span class="p">,</span> <span class="n">id</span><span class="p">,</span> <span class="s">"işliyor:"</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">&lt;-</span> <span class="n">fetch</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">urls</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
        <span class="s">"https://example.com"</span><span class="p">,</span>
        <span class="s">"https://go.dev"</span><span class="p">,</span>
        <span class="s">"https://pkg.go.dev"</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="n">client</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">http</span><span class="o">.</span><span class="n">Client</span><span class="p">{</span><span class="n">Timeout</span><span class="o">:</span> <span class="m">8</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">}</span>
    <span class="n">jobs</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">string</span><span class="p">)</span>
    <span class="n">results</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="n">Result</span><span class="p">)</span>

    <span class="k">var</span> <span class="n">wg</span> <span class="n">sync</span><span class="o">.</span><span class="n">WaitGroup</span>
    <span class="n">workerCount</span> <span class="o">:=</span> <span class="m">3</span>

    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">workerCount</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="n">wg</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
        <span class="k">go</span> <span class="n">worker</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">jobs</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">wg</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">url</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">urls</span> <span class="p">{</span>
            <span class="n">jobs</span> <span class="o">&lt;-</span> <span class="n">url</span>
        <span class="p">}</span>
        <span class="nb">close</span><span class="p">(</span><span class="n">jobs</span><span class="p">)</span>
        <span class="n">wg</span><span class="o">.</span><span class="n">Wait</span><span class="p">()</span>
        <span class="nb">close</span><span class="p">(</span><span class="n">results</span><span class="p">)</span>
    <span class="p">}()</span>

    <span class="k">for</span> <span class="n">r</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">results</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">r</span><span class="o">.</span><span class="n">Err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
            <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Hata:"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Err</span><span class="p">)</span>
            <span class="k">continue</span>
        <span class="p">}</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">URL</span><span class="p">,</span> <span class="s">"boyut:"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">Length</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Kodda <code class="language-plaintext highlighter-rouge">http.Client</code> için timeout vermek küçük ama hayati bir ayrıntıdır. Timeout yoksa bir istek sonsuza kadar asılı kalabilir ve scraper’ınız kahve molasından dönmeyen stajyer gibi ortadan kaybolur. <code class="language-plaintext highlighter-rouge">workerCount</code> değeri ise hız ile nezaket arasındaki dengedir. Çok düşük olursa yavaş kalırsınız, çok yüksek olursa hedef site sizi engelleyebilir.</p>

<p>HTML ayrıştırmak için standart kütüphane yeterli olmayabilir. Go ekosisteminde <code class="language-plaintext highlighter-rouge">goquery</code>, jQuery benzeri seçicilerle pratik bir çözüm sunar. Örneğin <code class="language-plaintext highlighter-rouge">h1</code>, <code class="language-plaintext highlighter-rouge">.price</code>, <code class="language-plaintext highlighter-rouge">a[href]</code> gibi seçicilerle veri çekilebilir. Fakat dinamik olarak JavaScript ile oluşan sayfalarda klasik HTTP isteği yetmez; bu durumda tarayıcı otomasyonu veya API keşfi gerekir.</p>

<table>
  <thead>
    <tr>
      <th>Konu</th>
      <th>Dikkat Edilecek Nokta</th>
      <th>İyi Uygulama</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Robots.txt</td>
      <td>Site taramaya izin vermeyebilir</td>
      <td>Önce kontrol et</td>
    </tr>
    <tr>
      <td>Rate limit</td>
      <td>Çok sık istek engellenir</td>
      <td>Gecikme ve worker limiti kullan</td>
    </tr>
    <tr>
      <td>User-Agent</td>
      <td>Varsayılan istemci şüpheli görünebilir</td>
      <td>Açıklayıcı User-Agent gönder</td>
    </tr>
    <tr>
      <td>Retry</td>
      <td>Geçici ağ hataları olabilir</td>
      <td>Üstel geri çekilme uygula</td>
    </tr>
    <tr>
      <td>Veri temizliği</td>
      <td>HTML gürültülüdür</td>
      <td>Normalize et ve doğrula</td>
    </tr>
  </tbody>
</table>

<p>Sonuç olarak Go ile scraper yazmak sadece hızlı istek göndermek değildir; küçük bir dağıtık sistem tasarlamaktır. Kuyruklar, worker’lar, timeout’lar ve hata yönetimi bir araya geldiğinde saniyeler içinde binlerce sayfayı gezebilen sağlam bir indeksleyici ortaya çıkar. Hız güzel, ama kontrollü hız daha güzeldir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="go" /><category term="web-scraping" /><category term="concurrency" /><category term="http" /><category term="goroutine" /><summary type="html"><![CDATA[İnternetteki veriler dağınık bir kütüphane gibidir: ürün fiyatları bir rafta, haber başlıkları başka rafta, açık veri tabloları ise bodrumda durur. Go ile yazılan bir web scraper, bu kütüphanede patenle gezen disiplinli bir arşivciye benzer. Hızlı HTTP istemcisi, goroutine yapısı ve channel mantığı sayesinde binlerce sayfayı kısa sürede ziyaret edip veriyi indeksleyebiliriz.]]></summary></entry><entry><title type="html">JavaScript ile Dinamik Socket İletişimi ve Anlık Bildirimler</title><link href="https://sonsuzus.github.io/posts/javascript-ile-dinamik-socket-iletisimi-ve-anlik-bildirimler/" rel="alternate" type="text/html" title="JavaScript ile Dinamik Socket İletişimi ve Anlık Bildirimler" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/javascript-ile-dinamik-socket-iletisimi-ve-anlik-bildirimler</id><content type="html" xml:base="https://sonsuzus.github.io/posts/javascript-ile-dinamik-socket-iletisimi-ve-anlik-bildirimler/"><![CDATA[<p>Bir forumda yeni cevap geldiğinde sayfayı yenilemeden bildirim almak ya da mesajlaşma uygulamasında karşı tarafın yazdığını anında görmek artık lüks değil, kullanıcı beklentisi. JavaScript ile dinamik socket iletişimi kurarak istemci ve sunucu arasında sürekli açık kalan, düşük gecikmeli bir kanal oluşturabiliriz. Amaç basit: kullanıcı beklemeden, sistem bağırmadan, veri doğru zamanda doğru kişiye ulaşsın.
``</p>

<h2 id="socket-mantığı-httpden-farkı-ne">Socket Mantığı: HTTP’den Farkı Ne?</h2>

<p>Klasik HTTP modelinde tarayıcı sunucuya istek atar, sunucu cevap verir ve bağlantı kapanır. Bu model forum sayfası yüklemek için harikadır; fakat “yeni mesaj var mı?” sorusunu her 2 saniyede bir sormak verimsizdir. Socket yaklaşımında ise bağlantı açık kalır. Sunucu, olay oluştuğunda istemciye kendisi veri gönderir.</p>

<p>Basit gecikme fikrini şöyle düşünebiliriz: $latency = t_{receive} - t_{send}$. Canlı bildirimlerde hedef bu değeri olabildiğince küçük tutmaktır. Polling’de bu süre istek aralığına bağlıyken, WebSocket’te olay gerçekleştiği anda veri kanala yazılır.</p>

<table>
  <thead>
    <tr>
      <th>Yöntem</th>
      <th>Çalışma Şekli</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Polling</td>
      <td>İstemci belirli aralıklarla sorar</td>
      <td>Kurulumu kolay</td>
      <td>Gereksiz trafik üretir</td>
    </tr>
    <tr>
      <td>Long Polling</td>
      <td>Sunucu cevap için bekler</td>
      <td>Daha az istek</td>
      <td>Bağlantı yönetimi karmaşıklaşır</td>
    </tr>
    <tr>
      <td>WebSocket</td>
      <td>İki yönlü açık kanal</td>
      <td>Gerçek zamanlı ve verimli</td>
      <td>Durum yönetimi gerekir</td>
    </tr>
    <tr>
      <td>Server-Sent Events</td>
      <td>Sunucudan istemciye tek yönlü akış</td>
      <td>Bildirim için pratik</td>
      <td>İstemciden sunucuya kanal yok</td>
    </tr>
  </tbody>
</table>

<h2 id="temel-mimari">Temel Mimari</h2>

<p>Canlı bildirim sisteminde genellikle üç ana parça vardır: istemci, socket sunucusu ve veri kaynağı. Kullanıcı yeni mesaj gönderdiğinde önce API veya socket sunucusu bu olayı alır. Ardından ilgili odaya, kullanıcıya veya gruba bildirim yayılır. Buradaki kritik kavram “room” yani odadır. Örneğin forumdaki her konu bir oda olabilir.</p>

\[aktifBildirimler = kullaniciSayisi * ortalamaOlayFrekansi\]

<p>Bu ifade bize ölçekleme baskısını hatırlatır. 10 kullanıcıda çalışan sistem, 10.000 kullanıcıda bağlantı, bellek ve yayın stratejisi ister.</p>

<h2 id="sunucu-tarafı-socketio-ile-başlangıç">Sunucu Tarafı: Socket.IO ile Başlangıç</h2>

<p>Aşağıdaki örnekte Node.js ve Socket.IO kullanıyoruz. Kodun görevi, kullanıcıyı ilgili forum konusunun odasına almak ve yeni cevap geldiğinde sadece o odaya bildirim göndermek.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Server</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">socket.io</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">http</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">http</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="nx">http</span><span class="p">.</span><span class="nf">createServer</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">io</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Server</span><span class="p">(</span><span class="nx">server</span><span class="p">,</span> <span class="p">{</span>
  <span class="na">cors</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">origin</span><span class="p">:</span> <span class="dl">'</span><span class="s1">http://localhost:3000</span><span class="dl">'</span>
  <span class="p">}</span>
<span class="p">});</span>

<span class="nx">io</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">connection</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">socket</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Bağlandı:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>

  <span class="nx">socket</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">forum:join</span><span class="dl">'</span><span class="p">,</span> <span class="p">({</span> <span class="nx">topicId</span><span class="p">,</span> <span class="nx">userId</span> <span class="p">})</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">socket</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">`topic:</span><span class="p">${</span><span class="nx">topicId</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
    <span class="nx">socket</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">userId</span> <span class="o">=</span> <span class="nx">userId</span><span class="p">;</span>
  <span class="p">});</span>

  <span class="nx">socket</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">forum:new-reply</span><span class="dl">'</span><span class="p">,</span> <span class="p">({</span> <span class="nx">topicId</span><span class="p">,</span> <span class="nx">message</span><span class="p">,</span> <span class="nx">author</span> <span class="p">})</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">io</span><span class="p">.</span><span class="nf">to</span><span class="p">(</span><span class="s2">`topic:</span><span class="p">${</span><span class="nx">topicId</span><span class="p">}</span><span class="s2">`</span><span class="p">).</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">notification:new</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
      <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">reply</span><span class="dl">'</span><span class="p">,</span>
      <span class="nx">topicId</span><span class="p">,</span>
      <span class="nx">message</span><span class="p">,</span>
      <span class="nx">author</span><span class="p">,</span>
      <span class="na">sentAt</span><span class="p">:</span> <span class="nb">Date</span><span class="p">.</span><span class="nf">now</span><span class="p">()</span>
    <span class="p">});</span>
  <span class="p">});</span>

  <span class="nx">socket</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">disconnect</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Ayrıldı:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
  <span class="p">});</span>
<span class="p">});</span>

<span class="nx">server</span><span class="p">.</span><span class="nf">listen</span><span class="p">(</span><span class="mi">4000</span><span class="p">);</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">forum:join</code> istemcinin hangi konuyu dinleyeceğini belirler. <code class="language-plaintext highlighter-rouge">forum:new-reply</code> ise yeni cevap olayını alır ve sadece <code class="language-plaintext highlighter-rouge">topic:123</code> gibi ilgili odaya yayın yapar. Böylece herkes her bildirimi almaz; sistem daha temiz ve ekonomik çalışır.</p>

<h2 id="i̇stemci-tarafı-dinleme-ve-yeniden-bağlanma">İstemci Tarafı: Dinleme ve Yeniden Bağlanma</h2>

<p>Tarayıcı tarafında bağlantı kurar, odaya katılır ve bildirim olaylarını dinleriz. Bağlantı koparsa Socket.IO otomatik yeniden bağlanmayı destekler; yine de kullanıcı deneyimi için durum bilgisini göstermek akıllıcadır.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">io</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">socket.io-client</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">socket</span> <span class="o">=</span> <span class="nf">io</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://localhost:4000</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
  <span class="na">transports</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">websocket</span><span class="dl">'</span><span class="p">],</span>
  <span class="na">reconnectionAttempts</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
  <span class="na">reconnectionDelay</span><span class="p">:</span> <span class="mi">1000</span>
<span class="p">});</span>

<span class="nx">socket</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">connect</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Canlı kanal açık</span><span class="dl">'</span><span class="p">);</span>
  <span class="nx">socket</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">forum:join</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">topicId</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="na">userId</span><span class="p">:</span> <span class="mi">7</span> <span class="p">});</span>
<span class="p">});</span>

<span class="nx">socket</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">notification:new</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">payload</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Yeni bildirim:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
  <span class="nf">showToast</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">payload</span><span class="p">.</span><span class="nx">author</span><span class="p">}</span><span class="s2">: </span><span class="p">${</span><span class="nx">payload</span><span class="p">.</span><span class="nx">message</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">});</span>

<span class="nx">socket</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">disconnect</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Bağlantı koptu, tekrar deneniyor...</span><span class="dl">'</span><span class="p">);</span>
<span class="p">});</span>

<span class="kd">function</span> <span class="nf">showToast</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">div</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">div</span><span class="dl">'</span><span class="p">);</span>
  <span class="nx">div</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">text</span><span class="p">;</span>
  <span class="nx">div</span><span class="p">.</span><span class="nx">className</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">toast</span><span class="dl">'</span><span class="p">;</span>
  <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">div</span><span class="p">);</span>
  <span class="nf">setTimeout</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">div</span><span class="p">.</span><span class="nf">remove</span><span class="p">(),</span> <span class="mi">4000</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu yapı sayesinde kullanıcı forum konusunu açık tutarken yeni cevapları anında görür. Mesajlaşma platformunda da aynı mantık <code class="language-plaintext highlighter-rouge">room:${conversationId}</code> ile uygulanabilir.</p>

<h2 id="güvenlik-ve-performans-i̇puçları">Güvenlik ve Performans İpuçları</h2>

<p>Socket bağlantısı açık diye her olaya güvenmemeliyiz. Kullanıcının gerçekten ilgili odaya erişim yetkisi var mı, sunucuda kontrol edilmelidir. Ayrıca olay adlarını standartlaştırmak, payload boyutunu küçük tutmak ve gereksiz yayınlardan kaçınmak gerekir.</p>

<table>
  <thead>
    <tr>
      <th>Problem</th>
      <th>Çözüm</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Herkese gereksiz bildirim gitmesi</td>
      <td>Room bazlı yayın kullan</td>
    </tr>
    <tr>
      <td>Bağlantı kopmaları</td>
      <td>Yeniden bağlanma stratejisi ekle</td>
    </tr>
    <tr>
      <td>Yetkisiz dinleme</td>
      <td>Token doğrulama yap</td>
    </tr>
    <tr>
      <td>Yüksek trafik</td>
      <td>Payload sadeleştir, Redis adapter kullan</td>
    </tr>
  </tbody>
</table>

<p>Özetle dinamik socket iletişimi, modern web uygulamalarının nabzıdır. Doğru oda modeli, güvenli kimlik doğrulama ve kontrollü yayın stratejisiyle forumlar, sohbetler ve bildirim panelleri gerçekten canlı hissettirilir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="javascript" /><category term="socket.io" /><category term="websocket" /><category term="anlık-bildirim" /><summary type="html"><![CDATA[Bir forumda yeni cevap geldiğinde sayfayı yenilemeden bildirim almak ya da mesajlaşma uygulamasında karşı tarafın yazdığını anında görmek artık lüks değil, kullanıcı beklentisi. JavaScript ile dinamik socket iletişimi kurarak istemci ve sunucu arasında sürekli açık kalan, düşük gecikmeli bir kanal oluşturabiliriz. Amaç basit: kullanıcı beklemeden, sistem bağırmadan, veri doğru zamanda doğru kişiye ulaşsın.]]></summary></entry><entry><title type="html">PHP ile RESTful API Tasarımı: Ortak Veritabanına Güvenli Köprü</title><link href="https://sonsuzus.github.io/posts/php-ile-restful-api-tasarimi-ortak-veritabanina-guvenli-kopru/" rel="alternate" type="text/html" title="PHP ile RESTful API Tasarımı: Ortak Veritabanına Güvenli Köprü" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/php-ile-restful-api-tasarimi-ortak-veritabanina-guvenli-kopru</id><content type="html" xml:base="https://sonsuzus.github.io/posts/php-ile-restful-api-tasarimi-ortak-veritabanina-guvenli-kopru/"><![CDATA[<p>Bir mobil uygulama, web paneli ve masaüstü istemcisi aynı veriye ulaşmak istediğinde ortada bir hakem gerekir: RESTful API. PHP ile yazacağımız API, cihazların doğrudan veritabanına dalmasını engeller; bunun yerine standart JSON yanıtları, HTTP metodları ve güvenlik katmanlarıyla düzenli bir trafik polisi gibi çalışır. Böylece iOS, Android, React, Vue ya da başka bir sistem aynı kurallarla konuşur.
``
REST mimarisinin temel fikri kaynak kavramıdır. Kullanıcılar, ürünler, siparişler gibi her şey birer resource olarak düşünülür. Örneğin <code class="language-plaintext highlighter-rouge">/api/users/15</code> adresi 15 numaralı kullanıcıyı temsil eder. Burada işlem türünü URL’ye fiil olarak yazmak yerine HTTP metodlarıyla anlatırız: listelemek için <code class="language-plaintext highlighter-rouge">GET</code>, oluşturmak için <code class="language-plaintext highlighter-rouge">POST</code>, güncellemek için <code class="language-plaintext highlighter-rouge">PUT/PATCH</code>, silmek için <code class="language-plaintext highlighter-rouge">DELETE</code>.</p>

<p>Küçük bir matematiksel sezgiyle API yükünü şöyle düşünebiliriz: Toplam istek maliyeti $T = n \times c$ olsun. Burada $n$ istek sayısı, $c$ ise her isteğin ortalama maliyetidir. Gereksiz büyük yanıtlar veya kötü sorgular $c$ değerini büyütür; sayfalama, filtreleme ve indeksli veritabanı sorguları ise API’yi hızlandırır.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Kötü Yaklaşım</th>
      <th>RESTful Yaklaşım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kullanıcı listeleme</td>
      <td><code class="language-plaintext highlighter-rouge">/getUsers.php</code></td>
      <td><code class="language-plaintext highlighter-rouge">GET /api/users</code></td>
    </tr>
    <tr>
      <td>Kullanıcı ekleme</td>
      <td><code class="language-plaintext highlighter-rouge">/addUser.php</code></td>
      <td><code class="language-plaintext highlighter-rouge">POST /api/users</code></td>
    </tr>
    <tr>
      <td>Yanıt formatı</td>
      <td>Karışık metin</td>
      <td>Standart JSON</td>
    </tr>
    <tr>
      <td>Hata yönetimi</td>
      <td>Her zaman 200</td>
      <td>Uygun HTTP durum kodu</td>
    </tr>
  </tbody>
</table>

<p>Standart yanıt yapısı API’nin farklı platformlarda tahmin edilebilir olmasını sağlar. Örneğin her cevapta <code class="language-plaintext highlighter-rouge">success</code>, <code class="language-plaintext highlighter-rouge">data</code>, <code class="language-plaintext highlighter-rouge">message</code> ve <code class="language-plaintext highlighter-rouge">errors</code> alanlarını kullanmak, istemci tarafındaki kodu sadeleştirir. Başarılı listeleme için durum kodu $200$, kayıt oluşturma için $201$, yetkisiz erişim için $401$, bulunamayan kaynak için $404$ tercih edilir.</p>

<p>Aşağıdaki örnek, basit ama düzenli bir PHP API iskeleti gösterir. PDO ile hazırlanmış sorgular SQL injection riskini azaltır, <code class="language-plaintext highlighter-rouge">json_response</code> fonksiyonu ise tüm çıktıları tek biçime sokar.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nb">header</span><span class="p">(</span><span class="s1">'Content-Type: application/json; charset=utf-8'</span><span class="p">);</span>

<span class="nv">$pdo</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PDO</span><span class="p">(</span>
    <span class="s1">'mysql:host=localhost;dbname=app;charset=utf8mb4'</span><span class="p">,</span>
    <span class="s1">'api_user'</span><span class="p">,</span>
    <span class="s1">'secret_password'</span><span class="p">,</span>
    <span class="p">[</span><span class="no">PDO</span><span class="o">::</span><span class="no">ATTR_ERRMODE</span> <span class="o">=&gt;</span> <span class="no">PDO</span><span class="o">::</span><span class="no">ERRMODE_EXCEPTION</span><span class="p">]</span>
<span class="p">);</span>

<span class="k">function</span> <span class="n">json_response</span><span class="p">(</span><span class="nv">$status</span><span class="p">,</span> <span class="nv">$success</span><span class="p">,</span> <span class="nv">$data</span> <span class="o">=</span> <span class="kc">null</span><span class="p">,</span> <span class="nv">$message</span> <span class="o">=</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$errors</span> <span class="o">=</span> <span class="p">[])</span> <span class="p">{</span>
    <span class="nb">http_response_code</span><span class="p">(</span><span class="nv">$status</span><span class="p">);</span>
    <span class="k">echo</span> <span class="nb">json_encode</span><span class="p">([</span>
        <span class="s1">'success'</span> <span class="o">=&gt;</span> <span class="nv">$success</span><span class="p">,</span>
        <span class="s1">'data'</span> <span class="o">=&gt;</span> <span class="nv">$data</span><span class="p">,</span>
        <span class="s1">'message'</span> <span class="o">=&gt;</span> <span class="nv">$message</span><span class="p">,</span>
        <span class="s1">'errors'</span> <span class="o">=&gt;</span> <span class="nv">$errors</span>
    <span class="p">],</span> <span class="no">JSON_UNESCAPED_UNICODE</span><span class="p">);</span>
    <span class="k">exit</span><span class="p">;</span>
<span class="p">}</span>

<span class="nv">$method</span> <span class="o">=</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">'REQUEST_METHOD'</span><span class="p">];</span>
<span class="nv">$path</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nb">parse_url</span><span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">'REQUEST_URI'</span><span class="p">],</span> <span class="kc">PHP_URL_PATH</span><span class="p">),</span> <span class="s1">'/'</span><span class="p">);</span>
<span class="nv">$parts</span> <span class="o">=</span> <span class="nb">explode</span><span class="p">(</span><span class="s1">'/'</span><span class="p">,</span> <span class="nv">$path</span><span class="p">);</span>

<span class="k">if</span> <span class="p">(</span><span class="nv">$parts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!==</span> <span class="s1">'api'</span> <span class="o">||</span> <span class="nv">$parts</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!==</span> <span class="s1">'users'</span><span class="p">)</span> <span class="p">{</span>
    <span class="nf">json_response</span><span class="p">(</span><span class="mi">404</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="s1">'Kaynak bulunamadı'</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">if</span> <span class="p">(</span><span class="nv">$method</span> <span class="o">===</span> <span class="s1">'GET'</span><span class="p">)</span> <span class="p">{</span>
    <span class="nv">$stmt</span> <span class="o">=</span> <span class="nv">$pdo</span><span class="o">-&gt;</span><span class="nf">query</span><span class="p">(</span><span class="s1">'SELECT id, name, email FROM users ORDER BY id DESC LIMIT 20'</span><span class="p">);</span>
    <span class="nf">json_response</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="kc">true</span><span class="p">,</span> <span class="nv">$stmt</span><span class="o">-&gt;</span><span class="nf">fetchAll</span><span class="p">(</span><span class="no">PDO</span><span class="o">::</span><span class="no">FETCH_ASSOC</span><span class="p">),</span> <span class="s1">'Kullanıcılar listelendi'</span><span class="p">);</span>
<span class="p">}</span>

<span class="nf">json_response</span><span class="p">(</span><span class="mi">405</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="s1">'Bu metod desteklenmiyor'</span><span class="p">);</span>
</code></pre></div></div>

<p>Bu kodun yaptığı şey basit: Gelen isteğin metodunu ve yolunu okur, <code class="language-plaintext highlighter-rouge">/api/users</code> kaynağına gelen <code class="language-plaintext highlighter-rouge">GET</code> isteklerinde kullanıcıları JSON olarak döndürür. Gerçek projede bu yönlendirme mantığını ayrı bir router sınıfına almak, controller katmanı eklemek ve veritabanı işlemlerini repository yapısına taşımak daha sürdürülebilir olur.</p>

<p>Güvenlik tarafında en kritik konu kimlik doğrulamadır. Oturum tabanlı klasik yaklaşım yerine API’lerde genellikle token kullanılır. Kullanıcı giriş yapınca bir erişim token’ı alır ve sonraki isteklerde <code class="language-plaintext highlighter-rouge">Authorization: Bearer TOKEN</code> başlığıyla gönderir. Token doğrulanmadan hassas kaynaklara erişim verilmemelidir.</p>

<table>
  <thead>
    <tr>
      <th>Önlem</th>
      <th>Neden Gerekli?</th>
      <th>PHP Tarafındaki Karşılığı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>HTTPS</td>
      <td>Token sızıntısını önler</td>
      <td>Sunucu SSL yapılandırması</td>
    </tr>
    <tr>
      <td>Prepared statement</td>
      <td>SQL injection engeller</td>
      <td>PDO parametre bağlama</td>
    </tr>
    <tr>
      <td>Rate limit</td>
      <td>Bot saldırılarını yavaşlatır</td>
      <td>IP bazlı sayaç</td>
    </tr>
    <tr>
      <td>CORS kontrolü</td>
      <td>İzinli istemcileri belirler</td>
      <td><code class="language-plaintext highlighter-rouge">Access-Control-Allow-Origin</code></td>
    </tr>
  </tbody>
</table>

<p>Basit bir token kontrolü şöyle kurgulanabilir:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="n">require_token</span><span class="p">()</span> <span class="p">{</span>
    <span class="nv">$headers</span> <span class="o">=</span> <span class="nb">getallheaders</span><span class="p">();</span>
    <span class="nv">$auth</span> <span class="o">=</span> <span class="nv">$headers</span><span class="p">[</span><span class="s1">'Authorization'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">str_starts_with</span><span class="p">(</span><span class="nv">$auth</span><span class="p">,</span> <span class="s1">'Bearer '</span><span class="p">))</span> <span class="p">{</span>
        <span class="nf">json_response</span><span class="p">(</span><span class="mi">401</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="s1">'Token eksik'</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nv">$token</span> <span class="o">=</span> <span class="nb">substr</span><span class="p">(</span><span class="nv">$auth</span><span class="p">,</span> <span class="mi">7</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="nv">$token</span> <span class="o">!==</span> <span class="s1">'demo-secure-token'</span><span class="p">)</span> <span class="p">{</span>
        <span class="nf">json_response</span><span class="p">(</span><span class="mi">403</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="s1">'Token geçersiz'</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Elbette canlı sistemde sabit token kullanılmaz; JWT, OAuth2 veya veritabanında saklanan süreli erişim anahtarları tercih edilir. Ayrıca API sürümleme unutulmamalıdır: <code class="language-plaintext highlighter-rouge">/api/v1/users</code> gibi bir yapı, ileride kırıcı değişiklikleri yönetmeyi kolaylaştırır.</p>

<p>Sonuç olarak PHP ile RESTful API tasarlamak, yalnızca birkaç endpoint yazmak değildir. Kaynak modelleme, HTTP semantiği, güvenlik, hata standardı ve performans bir araya geldiğinde platform bağımsız, güvenilir ve keyifli bir veri köprüsü ortaya çıkar. Doğru kuralları koyarsanız, cihazlarınız aynı veritabanıyla kavga etmeden konuşur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="PHP" /><category term="RESTful API" /><category term="Backend" /><summary type="html"><![CDATA[Bir mobil uygulama, web paneli ve masaüstü istemcisi aynı veriye ulaşmak istediğinde ortada bir hakem gerekir: RESTful API. PHP ile yazacağımız API, cihazların doğrudan veritabanına dalmasını engeller; bunun yerine standart JSON yanıtları, HTTP metodları ve güvenlik katmanlarıyla düzenli bir trafik polisi gibi çalışır. Böylece iOS, Android, React, Vue ya da başka bir sistem aynı kurallarla konuşur.]]></summary></entry><entry><title type="html">Python ile Konteyner Yönetimi API’leri: Minik Sanal Kafeslerin Otomasyonu</title><link href="https://sonsuzus.github.io/posts/python-ile-konteyner-yonetimi-apileri-minik-sanal-kafeslerin-otomasyonu/" rel="alternate" type="text/html" title="Python ile Konteyner Yönetimi API’leri: Minik Sanal Kafeslerin Otomasyonu" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/python-ile-konteyner-yonetimi-apileri-minik-sanal-kafeslerin-otomasyonu</id><content type="html" xml:base="https://sonsuzus.github.io/posts/python-ile-konteyner-yonetimi-apileri-minik-sanal-kafeslerin-otomasyonu/"><![CDATA[<p>Bir uygulamayı çalıştırırken “benim bilgisayarımda çalışıyordu” cümlesini tarihe gömmek istiyorsak, konteynerler en eğlenceli araçlardan biridir. Python ile konteyner yönetimi API’leri ise bu küçük, izole çalışma ortamlarını elle komut yazmadan oluşturmayı, başlatmayı, durdurmayı ve gözlemlemeyi sağlar. Yani terminalde tek tek <code class="language-plaintext highlighter-rouge">docker run</code> yazmak yerine, orkestrayı Python şefliğinde yönetiriz.
``</p>

<p>Konteyner mantığını anlamak için önce şu fikri netleştirelim: Konteyner, tam bir sanal makine değildir. İşletim sisteminin çekirdeğini paylaşır; fakat dosya sistemi, ağ, süreçler ve ortam değişkenleri açısından izole davranır. Bu yüzden hızlı başlar, az kaynak tüketir ve taşınabilirdir. Basitçe kaynak maliyetini şöyle düşünebiliriz: $M_{toplam}=M_{imaj}+M_{runtime}+M_{veri}$. Sanal makinelerde buna çoğu zaman ayrı bir işletim sistemi maliyeti de eklenir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Sanal Makine</th>
      <th>Konteyner</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Başlama süresi</td>
      <td>Dakikalar olabilir</td>
      <td>Genellikle saniyeler</td>
    </tr>
    <tr>
      <td>İzolasyon</td>
      <td>Çok güçlü, ayrı OS</td>
      <td>Güçlü, paylaşılan kernel</td>
    </tr>
    <tr>
      <td>Kaynak kullanımı</td>
      <td>Daha yüksek</td>
      <td>Daha düşük</td>
    </tr>
    <tr>
      <td>Taşınabilirlik</td>
      <td>Orta</td>
      <td>Çok yüksek</td>
    </tr>
    <tr>
      <td>Tipik kullanım</td>
      <td>Tam sistem simülasyonu</td>
      <td>Uygulama dağıtımı</td>
    </tr>
  </tbody>
</table>

<p>Python tarafında en yaygın yaklaşım Docker Engine API ile konuşmaktır. Docker aslında arka planda bir HTTP API sunar; <code class="language-plaintext highlighter-rouge">docker</code> komutu da bu API’ye istek atan bir istemcidir. Python’da <code class="language-plaintext highlighter-rouge">docker</code> SDK kullanarak bu API’ye zarifçe bağlanırız. Böylece uygulama konteyneri, PostgreSQL konteyneri, test veritabanı veya geçici worker süreçleri kodla yönetilebilir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">docker</span>

<span class="n">client</span> <span class="o">=</span> <span class="n">docker</span><span class="p">.</span><span class="nf">from_env</span><span class="p">()</span>

<span class="n">container</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="n">containers</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span>
    <span class="sh">'</span><span class="s">nginx:alpine</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">name</span><span class="o">=</span><span class="sh">'</span><span class="s">mini-web</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">ports</span><span class="o">=</span><span class="p">{</span><span class="sh">'</span><span class="s">80/tcp</span><span class="sh">'</span><span class="p">:</span> <span class="mi">8080</span><span class="p">},</span>
    <span class="n">detach</span><span class="o">=</span><span class="bp">True</span>
<span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">Konteyner başladı:</span><span class="sh">'</span><span class="p">,</span> <span class="n">container</span><span class="p">.</span><span class="nb">id</span><span class="p">[:</span><span class="mi">12</span><span class="p">])</span>
</code></pre></div></div>

<p>Bu kod, yerel Docker ortamına bağlanır, <code class="language-plaintext highlighter-rouge">nginx:alpine</code> imajından bir konteyner başlatır ve konteynerin 80 portunu makinedeki 8080 portuna bağlar. <code class="language-plaintext highlighter-rouge">detach=True</code>, sürecin arka planda çalışmasını sağlar. Buradaki kritik düşünce şudur: Python kodu artık altyapıyı tarif eden küçük bir otomasyon robotudur.</p>

<p>Veritabanı senaryosu daha da ilginçtir. Diyelim ki her test çalışmasında temiz bir PostgreSQL istiyorsunuz. Konteyner API’siyle test başlamadan veritabanını ayağa kaldırır, test bitince yok edersiniz. Bu yaklaşım özellikle CI/CD hatlarında çok değerlidir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">docker</span>
<span class="kn">import</span> <span class="n">time</span>

<span class="n">client</span> <span class="o">=</span> <span class="n">docker</span><span class="p">.</span><span class="nf">from_env</span><span class="p">()</span>

<span class="n">db</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="n">containers</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span>
    <span class="sh">'</span><span class="s">postgres:16-alpine</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">name</span><span class="o">=</span><span class="sh">'</span><span class="s">test-postgres</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">environment</span><span class="o">=</span><span class="p">{</span>
        <span class="sh">'</span><span class="s">POSTGRES_PASSWORD</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">secret</span><span class="sh">'</span><span class="p">,</span>
        <span class="sh">'</span><span class="s">POSTGRES_DB</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">appdb</span><span class="sh">'</span>
    <span class="p">},</span>
    <span class="n">ports</span><span class="o">=</span><span class="p">{</span><span class="sh">'</span><span class="s">5432/tcp</span><span class="sh">'</span><span class="p">:</span> <span class="mi">55432</span><span class="p">},</span>
    <span class="n">detach</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
    <span class="n">remove</span><span class="o">=</span><span class="bp">True</span>
<span class="p">)</span>

<span class="n">time</span><span class="p">.</span><span class="nf">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">Test veritabanı hazır:</span><span class="sh">'</span><span class="p">,</span> <span class="n">db</span><span class="p">.</span><span class="n">name</span><span class="p">)</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">environment</code> parametresi konteyner içindeki ortam değişkenlerini belirler. <code class="language-plaintext highlighter-rouge">remove=True</code>, konteyner durunca otomatik temizlenmesini sağlar. Elbette gerçek projede <code class="language-plaintext highlighter-rouge">sleep</code> yerine sağlık kontrolü yapmak daha doğru olur; çünkü veritabanının hazır olma süresi makineye göre değişebilir.</p>

<p>Konteyner yönetiminde yaşam döngüsü genellikle şu adımlardan oluşur:</p>

<table>
  <thead>
    <tr>
      <th>Aşama</th>
      <th>API işlemi</th>
      <th>Amaç</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Oluşturma</td>
      <td><code class="language-plaintext highlighter-rouge">containers.run</code> veya <code class="language-plaintext highlighter-rouge">create</code></td>
      <td>İmajdan yeni ortam üretmek</td>
    </tr>
    <tr>
      <td>Başlatma</td>
      <td><code class="language-plaintext highlighter-rouge">start</code></td>
      <td>Süreci çalıştırmak</td>
    </tr>
    <tr>
      <td>İzleme</td>
      <td><code class="language-plaintext highlighter-rouge">logs</code>, <code class="language-plaintext highlighter-rouge">stats</code></td>
      <td>Çıktı ve kaynak takibi</td>
    </tr>
    <tr>
      <td>Durdurma</td>
      <td><code class="language-plaintext highlighter-rouge">stop</code></td>
      <td>Kontrollü kapatma</td>
    </tr>
    <tr>
      <td>Temizleme</td>
      <td><code class="language-plaintext highlighter-rouge">remove</code></td>
      <td>Artıkları silmek</td>
    </tr>
  </tbody>
</table>

<p>Kaynak tüketimini izlemek de otomasyonun önemli parçasıdır. Örneğin bir konteynerin CPU kullanımını yaklaşık olarak $CPU\%=\frac{container_delta}{system_delta}\times cores\times100$ mantığıyla yorumlarız. Docker SDK, ham istatistikleri verir; siz bu verilerden alarm, rapor veya otomatik ölçekleme kararları üretebilirsiniz.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">container</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="n">containers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">mini-web</span><span class="sh">'</span><span class="p">)</span>

<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">container</span><span class="p">.</span><span class="nf">logs</span><span class="p">(</span><span class="n">stream</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">tail</span><span class="o">=</span><span class="mi">5</span><span class="p">):</span>
    <span class="nf">print</span><span class="p">(</span><span class="n">line</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">).</span><span class="nf">strip</span><span class="p">())</span>
</code></pre></div></div>

<p>Bu örnek, çalışan bir konteynerin loglarını akış halinde okur. Log okuma; hata ayıklama, canlı izleme ve otomatik analiz için temel bir tekniktir. Bir uygulama 500 hatası üretmeye başladığında Python betiğiniz bunu yakalayıp Slack mesajı atabilir, yeni konteyner başlatabilir veya sorunlu olanı yeniden başlatabilir.</p>

<p>Tabii güç arttıkça sorumluluk da artar. Konteyner API’lerine erişen Python kodu, sistemde ciddi yetkilere sahip olabilir. Bu yüzden socket erişimini sınırlamak, gizli bilgileri koda gömmemek, imajları güvenilir kaynaklardan çekmek ve ağ yapılandırmasını bilinçli yapmak gerekir.</p>

<p>Sonuç olarak Python ile konteyner yönetimi API’leri, uygulama ve veritabanlarını küçük sanal odalara yerleştirip bu odaların ışığını, kapısını, havalandırmasını kodla kontrol etmeye benzer. Geliştirme ortamı kurma, entegrasyon testi, geçici servis çalıştırma ve mini DevOps otomasyonları için oldukça güçlü bir yaklaşımdır. Birkaç satır Python ile altyapıya dokunmak hem pratik hem de biraz sihirli hissettirir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="python" /><category term="docker" /><category term="konteyner" /><category term="api" /><category term="devops" /><summary type="html"><![CDATA[Bir uygulamayı çalıştırırken “benim bilgisayarımda çalışıyordu” cümlesini tarihe gömmek istiyorsak, konteynerler en eğlenceli araçlardan biridir. Python ile konteyner yönetimi API’leri ise bu küçük, izole çalışma ortamlarını elle komut yazmadan oluşturmayı, başlatmayı, durdurmayı ve gözlemlemeyi sağlar. Yani terminalde tek tek docker run yazmak yerine, orkestrayı Python şefliğinde yönetiriz.]]></summary></entry><entry><title type="html">Python ve Cronjobs ile Otomatik API Raporlama Sistemi Kurmak</title><link href="https://sonsuzus.github.io/posts/python-ve-cronjobs-ile-otomatik-api-raporlama-sistemi-kurmak/" rel="alternate" type="text/html" title="Python ve Cronjobs ile Otomatik API Raporlama Sistemi Kurmak" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/python-ve-cronjobs-ile-otomatik-api-raporlama-sistemi-kurmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/python-ve-cronjobs-ile-otomatik-api-raporlama-sistemi-kurmak/"><![CDATA[<p>Sunucunuzun her sabah siz kahvenizi almadan önce API’lerden veri çekip rapor hazırladığını hayal edin. İşte Python ve cronjobs ikilisi tam olarak bu küçük dijital asistanı kurmanızı sağlar: Python işi yapar, cron ise doğru zamanda düğmeye basar.
``
Cronjob, Unix/Linux sistemlerde belirli zamanlarda komut çalıştıran zamanlayıcıdır. Python ise API istekleri, veri işleme, dosya üretme ve e-posta gönderme gibi görevlerde oldukça rahattır. Bu ikiliyle örneğin her gün saat 09:00’da satış API’sinden veri çekebilir, toplam geliri hesaplayabilir ve CSV raporu oluşturabilirsiniz.</p>

<h2 id="temel-mantık">Temel Mantık</h2>

<p>Cron’u bir çalar saat, Python scriptini de o alarm çalınca mutfağa gidip kahve yapan robot gibi düşünebiliriz. Cron sadece zamanı bilir; işin detayını Python yapar. Matematiksel olarak periyodik bir görevi şöyle ifade edebiliriz: $T = n \times \Delta t$. Burada $\Delta t$ çalıştırma aralığı, $n$ tekrar sayısıdır. Örneğin 24 saat boyunca her 1 saatte bir çalışan görev için $T = 24 \times 1$ olur.</p>

<p>Raporlama tarafında ise genellikle bir özet değer hesaplarız. Örneğin günlük toplam satış: $R = \sum_{i=1}^{n} tutar_i$. Python bu toplamı API’den gelen JSON verisi üzerinden kolayca çıkarabilir.</p>

<table>
  <thead>
    <tr>
      <th>Bileşen</th>
      <th>Görevi</th>
      <th>Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Cron</td>
      <td>Zamanlama yapar</td>
      <td>Her gün 09:00</td>
    </tr>
    <tr>
      <td>Python</td>
      <td>Veriyi çeker ve işler</td>
      <td>API isteği, CSV üretimi</td>
    </tr>
    <tr>
      <td>API</td>
      <td>Ham veri sağlar</td>
      <td>Satış, stok, kullanıcı verisi</td>
    </tr>
    <tr>
      <td>Rapor</td>
      <td>Sonuçları sunar</td>
      <td>CSV, JSON, e-posta</td>
    </tr>
  </tbody>
</table>

<h2 id="python-ile-apiden-veri-çekme">Python ile API’den Veri Çekme</h2>

<p>Aşağıdaki örnek, sahte bir satış API’sinden veri çeker, toplam satış miktarını hesaplar ve günlük raporu CSV dosyasına yazar. Gerçek projelerde API anahtarını doğrudan koda yazmak yerine ortam değişkeni kullanmak daha güvenlidir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">csv</span>
<span class="kn">import</span> <span class="n">os</span>
<span class="kn">from</span> <span class="n">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="kn">import</span> <span class="n">requests</span>

<span class="n">API_URL</span> <span class="o">=</span> <span class="sh">'</span><span class="s">https://api.example.com/sales</span><span class="sh">'</span>
<span class="n">API_KEY</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="nf">getenv</span><span class="p">(</span><span class="sh">'</span><span class="s">SALES_API_KEY</span><span class="sh">'</span><span class="p">)</span>

<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
    <span class="sh">'</span><span class="s">Authorization</span><span class="sh">'</span><span class="p">:</span> <span class="sa">f</span><span class="sh">'</span><span class="s">Bearer </span><span class="si">{</span><span class="n">API_KEY</span><span class="si">}</span><span class="sh">'</span>
<span class="p">}</span>

<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">API_URL</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span>
<span class="n">response</span><span class="p">.</span><span class="nf">raise_for_status</span><span class="p">()</span>

<span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
<span class="n">items</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">sales</span><span class="sh">'</span><span class="p">,</span> <span class="p">[])</span>

<span class="n">total_amount</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">amount</span><span class="sh">'</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">)</span>
<span class="n">report_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">.</span><span class="nf">now</span><span class="p">().</span><span class="nf">strftime</span><span class="p">(</span><span class="sh">'</span><span class="s">%Y-%m-%d</span><span class="sh">'</span><span class="p">)</span>

<span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">report_</span><span class="si">{</span><span class="n">report_date</span><span class="si">}</span><span class="s">.csv</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">w</span><span class="sh">'</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="sh">''</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">writer</span> <span class="o">=</span> <span class="n">csv</span><span class="p">.</span><span class="nf">writer</span><span class="p">(</span><span class="nb">file</span><span class="p">)</span>
    <span class="n">writer</span><span class="p">.</span><span class="nf">writerow</span><span class="p">([</span><span class="sh">'</span><span class="s">date</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">sale_count</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">total_amount</span><span class="sh">'</span><span class="p">])</span>
    <span class="n">writer</span><span class="p">.</span><span class="nf">writerow</span><span class="p">([</span><span class="n">report_date</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">items</span><span class="p">),</span> <span class="n">total_amount</span><span class="p">])</span>

<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">Rapor hazır: </span><span class="si">{</span><span class="n">report_date</span><span class="si">}</span><span class="s">, toplam: </span><span class="si">{</span><span class="n">total_amount</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">requests.get</code> API çağrısını yapar, <code class="language-plaintext highlighter-rouge">response.raise_for_status</code> hatalı HTTP durumlarında scriptin sessizce devam etmesini engeller. <code class="language-plaintext highlighter-rouge">sum</code> fonksiyonu ise gelen kayıtların <code class="language-plaintext highlighter-rouge">amount</code> alanlarını toplar. Yani küçük ama işlevsel bir raporlama hattı kurmuş oluruz.</p>

<h2 id="cron-i̇fadesini-okumak">Cron İfadesini Okumak</h2>

<p>Cron satırları beş zaman alanı ve bir komuttan oluşur:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># dakika saat gün ay haftanın_günü komut</span>
0 9 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /usr/bin/python3 /home/app/reports/daily_report.py
</code></pre></div></div>

<p>Bu örnek her gün saat 09:00’da scripti çalıştırır. Yıldız karakteri tüm değerler anlamına gelir. Yani gün, ay ve haftanın günü fark etmez.</p>

<table>
  <thead>
    <tr>
      <th>Cron İfadesi</th>
      <th>Anlamı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">*/15 * * * *</code></td>
      <td>Her 15 dakikada bir</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">0 * * * *</code></td>
      <td>Her saatin başında</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">0 9 * * *</code></td>
      <td>Her gün 09:00’da</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">30 23 * * 5</code></td>
      <td>Her cuma 23:30’da</td>
    </tr>
  </tbody>
</table>

<p>Cron ayarlamak için terminalde şu komutu kullanabilirsiniz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab <span class="nt">-e</span>
</code></pre></div></div>

<p>Ardından cron satırınızı ekleyip kaydedersiniz. Scriptin çalıştığından emin olmak için log yönlendirmesi yapmak akıllıca olur:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 9 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /usr/bin/python3 /home/app/reports/daily_report.py <span class="o">&gt;&gt;</span> /home/app/logs/report.log 2&gt;&amp;1
</code></pre></div></div>

<p>Buradaki <code class="language-plaintext highlighter-rouge">&gt;&gt;</code> çıktıyı log dosyasına ekler, <code class="language-plaintext highlighter-rouge">2&gt;&amp;1</code> ise hata mesajlarını da aynı dosyaya gönderir. Böylece sorun çıktığında dedektif gibi terminal geçmişi aramak zorunda kalmazsınız.</p>

<h2 id="dikkat-edilmesi-gerekenler">Dikkat Edilmesi Gerekenler</h2>

<table>
  <thead>
    <tr>
      <th>Problem</th>
      <th>Çözüm</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Ortam değişkeni cron içinde görünmez</td>
      <td>Crontab içinde değişken tanımlayın veya <code class="language-plaintext highlighter-rouge">.env</code> okuyun</td>
    </tr>
    <tr>
      <td>Script elle çalışır ama cron’da çalışmaz</td>
      <td>Mutlak dosya yolları kullanın</td>
    </tr>
    <tr>
      <td>API bazen cevap vermez</td>
      <td>Timeout, retry ve hata loglama ekleyin</td>
    </tr>
    <tr>
      <td>Sunucu saat dilimi farklıdır</td>
      <td><code class="language-plaintext highlighter-rouge">timedatectl</code> ile timezone kontrol edin</td>
    </tr>
  </tbody>
</table>

<p>Sonuç olarak Python ve cronjobs, düşük maliyetli ama güçlü bir otomasyon altyapısı sunar. Büyük bir veri platformu kurmadan önce, basit bir script ve iyi ayarlanmış bir cron satırıyla günlük raporlarınızı otomatikleştirebilirsiniz. Küçük başlar, loglarınızı izler, hata yönetimini güçlendirirseniz bu yapı zamanla güvenilir bir mini veri operasyonuna dönüşür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="python" /><category term="cronjob" /><category term="otomasyon" /><category term="api" /><category term="raporlama" /><summary type="html"><![CDATA[Sunucunuzun her sabah siz kahvenizi almadan önce API’lerden veri çekip rapor hazırladığını hayal edin. İşte Python ve cronjobs ikilisi tam olarak bu küçük dijital asistanı kurmanızı sağlar: Python işi yapar, cron ise doğru zamanda düğmeye basar.]]></summary></entry><entry><title type="html">SQL ve Tam Metin Arama: Forumlar İçin Mini Arama Motoru Mantığı</title><link href="https://sonsuzus.github.io/posts/sql-ve-tam-metin-arama-forumlar-icin-mini-arama-motoru-mantigi/" rel="alternate" type="text/html" title="SQL ve Tam Metin Arama: Forumlar İçin Mini Arama Motoru Mantığı" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/sql-ve-tam-metin-arama-forumlar-icin-mini-arama-motoru-mantigi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/sql-ve-tam-metin-arama-forumlar-icin-mini-arama-motoru-mantigi/"><![CDATA[<p>Bir forumda yüz binlerce tartışma, bir blogda yıllarca birikmiş yazılar olduğunu düşünün. Kullanıcı arama kutusuna sadece iki kelime yazar: SQL indeks. Beklentisi nettir: saniyeler değil, milisaniyeler içinde en alakalı sonuçlar gelsin. İşte SQL tabanlı tam metin arama, klasik LIKE sorgularının el feneriyle mağara gezmesine benzeyen dünyasından çıkıp, elimize projektör ve harita verdiğimiz yerdir.
``</p>

<h2 id="neden-like-yetmez">Neden LIKE Yetmez?</h2>

<p>Klasik arama genellikle şöyle başlar:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span>
<span class="k">FROM</span> <span class="n">posts</span>
<span class="k">WHERE</span> <span class="n">content</span> <span class="k">LIKE</span> <span class="s1">'%veritabanı%'</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu sorgu küçük tabloda sevimlidir, ama milyon satırlık forumda kahve molası ister. Çünkü başında joker karakter olan <code class="language-plaintext highlighter-rouge">%kelime%</code> ifadesi çoğu durumda normal indeksi verimli kullanamaz. Veritabanı satır satır gezip metnin içinde kelime arar. Bu işlem yaklaşık olarak $O(n)$ maliyetlidir; yani veri büyüdükçe bekleme süresi de büyür.</p>

<p>Tam metin arama ise metni önceden parçalar, kelimeleri işler ve ters indeks denilen bir yapı kurar. Ters indeks mantığı basittir: kelimeden belgeye giden bir harita oluşturulur. Yani veritabanı artık belge içinde kelime aramaz; kelimenin geçtiği belgeleri doğrudan bulur.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Nasıl Çalışır</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>LIKE</td>
      <td>Metin içinde desen arar</td>
      <td>Basit ve her yerde çalışır</td>
      <td>Büyük veride yavaş</td>
    </tr>
    <tr>
      <td>B-Tree indeks</td>
      <td>Tam veya önek eşleşmelerde iyidir</td>
      <td>ID, tarih, kategori için hızlı</td>
      <td>Serbest metin için sınırlı</td>
    </tr>
    <tr>
      <td>Full-Text Search</td>
      <td>Kelime tabanlı indeks kullanır</td>
      <td>Alaka sıralaması yapabilir</td>
      <td>Dil ve yapılandırma ister</td>
    </tr>
  </tbody>
</table>

<h2 id="arama-motoru-mantığının-temeli">Arama Motoru Mantığının Temeli</h2>

<p>Tam metin aramada ilk adım tokenization, yani metni anlamlı parçalara ayırmaktır. Örneğin Kullanıcılar hızlı arama istiyor cümlesi kullanıcılar, hızlı, arama, istiyor gibi kelimelere bölünür. Ardından stop word temizliği yapılabilir. Türkçede ve, ile, bir gibi çok sık geçen ama anlam değeri düşük kelimeler atılabilir.</p>

<p>Sonra stemming veya lemmatization devreye girer. Amaç arama, aramak, arandı gibi varyasyonları ortak köke yaklaştırmaktır. PostgreSQL gibi sistemlerde dil yapılandırması bu yüzden önemlidir.</p>

<p>Alaka puanı genellikle kelime sıklığına ve nadirliğine dayanır. Basit bir model şöyle düşünülebilir:</p>

<p>$score = tf * log(N / df)$</p>

<p>Burada $tf$ kelimenin ilgili belgede kaç kez geçtiğini, $N$ toplam belge sayısını, $df$ ise kelimenin kaç belgede bulunduğunu gösterir. Yani nadir ama aranan kelimeler daha değerli hale gelir. Forumda veritabanı kelimesi binlerce kez geçebilir, ama gin index daha az yerde geçiyorsa daha ayırt edici olabilir.</p>

<h2 id="postgresql-ile-örnek-kurgu">PostgreSQL ile Örnek Kurgu</h2>

<p>PostgreSQL, tam metin arama konusunda oldukça güçlüdür. <code class="language-plaintext highlighter-rouge">tsvector</code> metnin indekslenmiş halini, <code class="language-plaintext highlighter-rouge">tsquery</code> ise arama ifadesini temsil eder.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">posts</span> <span class="p">(</span>
    <span class="n">id</span> <span class="nb">SERIAL</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span>
    <span class="n">title</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">content</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">search_vector</span> <span class="n">TSVECTOR</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Bu tabloda <code class="language-plaintext highlighter-rouge">search_vector</code>, başlık ve içerikten üretilmiş arama alanı olarak kullanılabilir. Başlığa daha fazla ağırlık vermek de mümkündür:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">UPDATE</span> <span class="n">posts</span>
<span class="k">SET</span> <span class="n">search_vector</span> <span class="o">=</span>
    <span class="n">setweight</span><span class="p">(</span><span class="n">to_tsvector</span><span class="p">(</span><span class="s1">'turkish'</span><span class="p">,</span> <span class="n">title</span><span class="p">),</span> <span class="s1">'A'</span><span class="p">)</span> <span class="o">||</span>
    <span class="n">setweight</span><span class="p">(</span><span class="n">to_tsvector</span><span class="p">(</span><span class="s1">'turkish'</span><span class="p">,</span> <span class="n">content</span><span class="p">),</span> <span class="s1">'B'</span><span class="p">);</span>
</code></pre></div></div>

<p>Burada başlık A ağırlığında, içerik B ağırlığında değerlendirilir. Böylece aranan kelime başlıkta geçiyorsa sonuç daha yukarı çıkabilir. Arama için ise şöyle bir sorgu yazılabilir:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">id</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span>
       <span class="n">ts_rank</span><span class="p">(</span><span class="n">search_vector</span><span class="p">,</span> <span class="n">plainto_tsquery</span><span class="p">(</span><span class="s1">'turkish'</span><span class="p">,</span> <span class="s1">'sql indeks'</span><span class="p">))</span> <span class="k">AS</span> <span class="n">rank</span>
<span class="k">FROM</span> <span class="n">posts</span>
<span class="k">WHERE</span> <span class="n">search_vector</span> <span class="o">@@</span> <span class="n">plainto_tsquery</span><span class="p">(</span><span class="s1">'turkish'</span><span class="p">,</span> <span class="s1">'sql indeks'</span><span class="p">)</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">rank</span> <span class="k">DESC</span>
<span class="k">LIMIT</span> <span class="mi">10</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu sorgu, kullanıcının yazdığı ifadeyi arama sorgusuna dönüştürür, eşleşen kayıtları bulur ve alaka puanına göre sıralar. Yani artık sadece bulmakla kalmayız; en mantıklı sonuçları en üste taşırız.</p>

<p>Performans için GIN indeksi eklemek gerekir:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">INDEX</span> <span class="n">posts_search_idx</span>
<span class="k">ON</span> <span class="n">posts</span>
<span class="k">USING</span> <span class="n">GIN</span> <span class="p">(</span><span class="n">search_vector</span><span class="p">);</span>
</code></pre></div></div>

<p>GIN indeksi, çok değerli metin alanları için ters indeks mantığını verimli uygular. Büyük forumlarda fark dramatik olabilir.</p>

<h2 id="mysql-ve-diğerleri">MySQL ve Diğerleri</h2>

<p>MySQL tarafında da <code class="language-plaintext highlighter-rouge">FULLTEXT</code> indeksi kullanılabilir:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">ALTER</span> <span class="k">TABLE</span> <span class="n">posts</span>
<span class="k">ADD</span> <span class="n">FULLTEXT</span> <span class="k">INDEX</span> <span class="n">post_fulltext_idx</span> <span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">content</span><span class="p">);</span>

<span class="k">SELECT</span> <span class="n">id</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span>
       <span class="k">MATCH</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span> <span class="n">AGAINST</span><span class="p">(</span><span class="s1">'sql indeks'</span> <span class="k">IN</span> <span class="k">NATURAL</span> <span class="k">LANGUAGE</span> <span class="k">MODE</span><span class="p">)</span> <span class="k">AS</span> <span class="n">score</span>
<span class="k">FROM</span> <span class="n">posts</span>
<span class="k">WHERE</span> <span class="k">MATCH</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span> <span class="n">AGAINST</span><span class="p">(</span><span class="s1">'sql indeks'</span> <span class="k">IN</span> <span class="k">NATURAL</span> <span class="k">LANGUAGE</span> <span class="k">MODE</span><span class="p">)</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">score</span> <span class="k">DESC</span><span class="p">;</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>PostgreSQL</th>
      <th>MySQL</th>
      <th>Elasticsearch</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>SQL içinde kullanım</td>
      <td>Çok güçlü</td>
      <td>Kolay</td>
      <td>Harici servis</td>
    </tr>
    <tr>
      <td>Dil işleme</td>
      <td>Esnek</td>
      <td>Orta</td>
      <td>Çok gelişmiş</td>
    </tr>
    <tr>
      <td>Ölçeklenebilirlik</td>
      <td>İyi</td>
      <td>İyi</td>
      <td>Çok yüksek</td>
    </tr>
    <tr>
      <td>Kurulum karmaşıklığı</td>
      <td>Orta</td>
      <td>Düşük</td>
      <td>Daha yüksek</td>
    </tr>
  </tbody>
</table>

<h2 id="pratik-tasarım-i̇puçları">Pratik Tasarım İpuçları</h2>

<p>Tam metin aramayı gerçek bir üründe kullanırken başlık, etiket ve içerik aynı öneme sahip olmamalıdır. Başlıkta geçen kelime genellikle daha değerlidir. Ayrıca arama kutusuna yazılan metni doğrudan karmaşık sorguya çevirmek yerine güvenli fonksiyonlar kullanmak gerekir.</p>

<p>Bir diğer önemli konu güncellemedir. Yazı değiştiğinde <code class="language-plaintext highlighter-rouge">search_vector</code> da güncellenmelidir. Bunun için trigger kullanılabilir veya uygulama katmanında kayıt güncellenirken arama alanı da yeniden oluşturulabilir.</p>

<p>Sonuç olarak SQL ile tam metin arama, küçük bir özellik gibi görünse de kullanıcı deneyimini doğrudan değiştirir. Doğru indeks, doğru ağırlıklandırma ve iyi bir alaka puanı ile forumunuz artık dev bir metin çöplüğü değil, kullanıcıların aradığını hızla bulduğu akıllı bir bilgi haritası olur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="SQL" /><category term="Full-Text Search" /><category term="Veritabanı" /><category term="Arama Motoru" /><summary type="html"><![CDATA[Bir forumda yüz binlerce tartışma, bir blogda yıllarca birikmiş yazılar olduğunu düşünün. Kullanıcı arama kutusuna sadece iki kelime yazar: SQL indeks. Beklentisi nettir: saniyeler değil, milisaniyeler içinde en alakalı sonuçlar gelsin. İşte SQL tabanlı tam metin arama, klasik LIKE sorgularının el feneriyle mağara gezmesine benzeyen dünyasından çıkıp, elimize projektör ve harita verdiğimiz yerdir.]]></summary></entry><entry><title type="html">C++ ile Yapay Sinir Ağları Temelleri: Vektörleri Hızlandır, Modeli Uyandır</title><link href="https://sonsuzus.github.io/posts/c-ile-yapay-sinir-aglari-temelleri-vektorleri-hizlandir-modeli-uyandir/" rel="alternate" type="text/html" title="C++ ile Yapay Sinir Ağları Temelleri: Vektörleri Hızlandır, Modeli Uyandır" /><published>2026-07-13T00:00:00+00:00</published><updated>2026-07-13T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-yapay-sinir-aglari-temelleri-vektorleri-hizlandir-modeli-uyandir</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-yapay-sinir-aglari-temelleri-vektorleri-hizlandir-modeli-uyandir/"><![CDATA[<p>Yapay sinir ağları kulağa çoğu zaman Python kütüphanelerinin sihirli düğmeleri gibi gelir; fakat sahnenin arkasında olan şey oldukça “mekanik”tir: vektörler çarpılır, matrisler toplanır, türevler hesaplanır ve bellekten veri taşınır. C++ burada devreye girer; çünkü düşük seviyeli bellek kontrolü sayesinde yalnızca modeli değil, modelin öğrenirken yürüdüğü matematiksel yolu da optimize edebiliriz.
``
Bir yapay sinir ağını en sade haliyle düşünelim: Girdi vektörü $x$, ağırlık matrisi $W$, bias vektörü $b$ ve aktivasyon fonksiyonu $f$. Tek katmanlı bir ileri yayılım şu şekilde yazılır: $y = f(Wx + b)$. Burada “öğrenme” dediğimiz şey, $W$ ve $b$ değerlerini kayıp fonksiyonunu azaltacak şekilde güncellemektir. Örneğin ortalama kare hata için $L = \frac{1}{n}\sum (\hat{y}-y)^2$ kullanabiliriz.</p>

<p>C++ ile çalışırken kritik soru şudur: Bu matematiksel ifadeleri bellekte nasıl temsil edeceğiz? Çünkü CPU, veriye hızlı erişirse hesaplama da hızlanır. Dağınık <code class="language-plaintext highlighter-rouge">std::vector&lt;std::vector&lt;float&gt;&gt;</code> yapıları okunabilir olsa da satırlar bellekte parçalı durabilir. Tek boyutlu, ardışık bir dizi ise cache dostudur.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Bellek Düzeni</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">vector&lt;vector&lt;float&gt;&gt;</code></td>
      <td>Parçalı</td>
      <td>Kolay anlaşılır</td>
      <td>Cache kaçırma olasılığı yüksek</td>
    </tr>
    <tr>
      <td>Tek boyutlu <code class="language-plaintext highlighter-rouge">vector&lt;float&gt;</code></td>
      <td>Ardışık</td>
      <td>Hızlı erişim, SIMD’ye uygun</td>
      <td>İndeks hesabı gerekir</td>
    </tr>
    <tr>
      <td>Ham pointer / aligned buffer</td>
      <td>Kontrollü</td>
      <td>En yüksek optimizasyon alanı</td>
      <td>Hata yapması kolay</td>
    </tr>
  </tbody>
</table>

<p>Bir matrisi tek boyutlu sakladığımızda $W_{ij}$ elemanına erişim formülü şöyledir: $index = i \times cols + j$. Bu küçük formül, C++ tarafında büyük performans farkları yaratabilir.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cmath&gt;</span><span class="cp">
</span>
<span class="k">struct</span> <span class="nc">DenseLayer</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">in</span><span class="p">,</span> <span class="n">out</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span> <span class="n">W</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span> <span class="n">b</span><span class="p">;</span>

    <span class="n">DenseLayer</span><span class="p">(</span><span class="kt">int</span> <span class="n">input</span><span class="p">,</span> <span class="kt">int</span> <span class="n">output</span><span class="p">)</span>
        <span class="o">:</span> <span class="n">in</span><span class="p">(</span><span class="n">input</span><span class="p">),</span> <span class="n">out</span><span class="p">(</span><span class="n">output</span><span class="p">),</span> <span class="n">W</span><span class="p">(</span><span class="n">input</span> <span class="o">*</span> <span class="n">output</span><span class="p">),</span> <span class="n">b</span><span class="p">(</span><span class="n">output</span><span class="p">)</span> <span class="p">{}</span>

    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span> <span class="n">forward</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span> <span class="n">y</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="mf">0.0f</span><span class="p">);</span>

        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">out</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">float</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
            <span class="k">const</span> <span class="kt">int</span> <span class="n">row</span> <span class="o">=</span> <span class="n">i</span> <span class="o">*</span> <span class="n">in</span><span class="p">;</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">in</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">sum</span> <span class="o">+=</span> <span class="n">W</span><span class="p">[</span><span class="n">row</span> <span class="o">+</span> <span class="n">j</span><span class="p">]</span> <span class="o">*</span> <span class="n">x</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
            <span class="p">}</span>
            <span class="n">y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">tanh</span><span class="p">(</span><span class="n">sum</span><span class="p">);</span> <span class="c1">// aktivasyon</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">y</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">W</code> matrisi tek boyutlu tutulur. <code class="language-plaintext highlighter-rouge">row + j</code> erişimi, satırdaki elemanları ardışık okuduğu için işlemci önbelleğiyle iyi anlaşır. Yani CPU’ya “al bakalım, sıradaki veriler tam yanında” demiş oluruz. Bu da özellikle büyük katmanlarda önemlidir.</p>

<p>Öğrenme aşamasında geri yayılım devreye girer. Temel fikir zincir kuralıdır: $\frac{\partial L}{\partial W} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial W}$. Ardından ağırlıklar şu şekilde güncellenir: $W := W - \eta \frac{\partial L}{\partial W}$. Buradaki $\eta$ öğrenme oranıdır; çok büyükse model zıplar, çok küçükse kaplumbağa gibi ilerler.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Matematiksel Rol</th>
      <th>C++ Optimizasyon Noktası</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Ağırlık matrisi</td>
      <td>Öğrenilen dönüşüm</td>
      <td>Ardışık bellek, hizalama</td>
    </tr>
    <tr>
      <td>Aktivasyon</td>
      <td>Doğrusal olmayanlık</td>
      <td>Hızlı fonksiyon seçimi</td>
    </tr>
    <tr>
      <td>Gradyan</td>
      <td>Güncelleme yönü</td>
      <td>Geçici kopyaları azaltma</td>
    </tr>
    <tr>
      <td>Batch</td>
      <td>Paralel veri işleme</td>
      <td>Döngü düzeni, SIMD, thread</td>
    </tr>
  </tbody>
</table>

<p>Performans için dikkat edilmesi gerekenlerden biri gereksiz kopyalardır. Büyük vektörleri fonksiyonlara değer ile geçirmek yerine <code class="language-plaintext highlighter-rouge">const reference</code> kullanmak gerekir. Ayrıca eğitim döngüsünde sürekli yeni bellek ayırmak pahalıdır; mümkünse buffer’lar önceden oluşturulmalı ve tekrar kullanılmalıdır.</p>

<p>Daha ileri seviyede <code class="language-plaintext highlighter-rouge">alignas(64)</code>, SIMD komutları, OpenMP veya BLAS kütüphaneleri kullanılabilir. Ancak temeli anlamadan bu araçlara atlamak, turbo motoru bisiklete takmaya benzer. Önce veri yerleşimi, döngü sırası ve matematiksel akış net olmalıdır.</p>

<p>C++ ile sinir ağı yazmak, hazır kütüphane kullanmaya göre daha zahmetlidir; fakat karşılığında modelin kalp atışını duyarsınız. Her çarpım, her toplama, her bellek erişimi sizin kontrolünüzdedir. İşte bu yüzden C++, yapay sinir ağlarını yalnızca kullanmak değil, gerçekten anlamak isteyenler için harika bir laboratuvardır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="C++" /><category term="Yapay Sinir Ağları" /><category term="Optimizasyon" /><summary type="html"><![CDATA[Yapay sinir ağları kulağa çoğu zaman Python kütüphanelerinin sihirli düğmeleri gibi gelir; fakat sahnenin arkasında olan şey oldukça “mekanik”tir: vektörler çarpılır, matrisler toplanır, türevler hesaplanır ve bellekten veri taşınır. C++ burada devreye girer; çünkü düşük seviyeli bellek kontrolü sayesinde yalnızca modeli değil, modelin öğrenirken yürüdüğü matematiksel yolu da optimize edebiliriz.]]></summary></entry><entry><title type="html">Go ile Ters Proxy Yönetimi: Güvenli ve Hafif Ağ Geçitleri</title><link href="https://sonsuzus.github.io/posts/go-ile-ters-proxy-yonetimi-guvenli-ve-hafif-ag-gecitleri/" rel="alternate" type="text/html" title="Go ile Ters Proxy Yönetimi: Güvenli ve Hafif Ağ Geçitleri" /><published>2026-07-13T00:00:00+00:00</published><updated>2026-07-13T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/go-ile-ters-proxy-yonetimi-guvenli-ve-hafif-ag-gecitleri</id><content type="html" xml:base="https://sonsuzus.github.io/posts/go-ile-ters-proxy-yonetimi-guvenli-ve-hafif-ag-gecitleri/"><![CDATA[<p>Modern web sistemlerinde istemci ile servisler arasına akıllı bir kapı koymak çoğu zaman hayat kurtarır. Go ile yazılmış hafif bir ters proxy, gelen HTTP trafiğini uygun backend servisine yönlendirebilir, temel güvenlik kontrolleri yapabilir ve yükü birden fazla sunucuya dağıtabilir. Üstelik Go’nun standart kütüphanesindeki <code class="language-plaintext highlighter-rouge">net/http</code> ve <code class="language-plaintext highlighter-rouge">httputil</code> paketleri sayesinde bunu devasa framework’lere ihtiyaç duymadan kurabilirsiniz.
``</p>

<p>Ters proxy, istemcinin gerçek uygulama sunucularıyla doğrudan konuşmasını engelleyen aracı katmandır. İstemci <code class="language-plaintext highlighter-rouge">api.ornek.com</code> adresine istek atar; ters proxy bu isteği arkadaki <code class="language-plaintext highlighter-rouge">service-1</code>, <code class="language-plaintext highlighter-rouge">service-2</code> veya <code class="language-plaintext highlighter-rouge">service-3</code> gibi sunuculara iletir. Böylece güvenlik, gözlemlenebilirlik, önbellekleme, TLS sonlandırma ve yük dengeleme tek noktadan yönetilebilir.</p>

<p>Temel farkı şöyle özetleyebiliriz:</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Forward Proxy</th>
      <th>Reverse Proxy</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kimi temsil eder?</td>
      <td>İstemciyi</td>
      <td>Sunucuyu</td>
    </tr>
    <tr>
      <td>Kullanım amacı</td>
      <td>İnternete kontrollü çıkış</td>
      <td>Servislere kontrollü giriş</td>
    </tr>
    <tr>
      <td>Gizlenen taraf</td>
      <td>Kullanıcı/istemci</td>
      <td>Backend sunucular</td>
    </tr>
    <tr>
      <td>Örnek</td>
      <td>Kurumsal internet proxy’si</td>
      <td>API Gateway, Nginx, Traefik</td>
    </tr>
  </tbody>
</table>

<p>Yük dengelemenin mantığı ise basit ama kritiktir. Elimizde $n$ adet backend varsa ve gelen toplam istek sayısı $R$ ise ideal durumda her sunucunun yaklaşık yükü şu olur: $R_i \approx \frac{R}{n}$. Gerçekte CPU, bellek, ağ gecikmesi ve hata oranları farklı olduğundan bu dağılım her zaman eşit değildir. Bu yüzden round-robin, weighted round-robin veya least-connections gibi algoritmalar kullanılır.</p>

<table>
  <thead>
    <tr>
      <th>Algoritma</th>
      <th>Mantık</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Round Robin</td>
      <td>Sırayla dağıtır</td>
      <td>Basit ve hızlı</td>
      <td>Sunucu gücünü dikkate almaz</td>
    </tr>
    <tr>
      <td>Weighted Round Robin</td>
      <td>Ağırlığa göre dağıtır</td>
      <td>Güçlü sunucuya daha çok trafik verir</td>
      <td>Ağırlık ayarı gerekir</td>
    </tr>
    <tr>
      <td>Least Connections</td>
      <td>En az bağlantılıya yollar</td>
      <td>Dinamik yüke duyarlı</td>
      <td>Takip maliyeti vardır</td>
    </tr>
  </tbody>
</table>

<p>Go’da en yalın ters proxy örneği <code class="language-plaintext highlighter-rouge">httputil.NewSingleHostReverseProxy</code> ile yazılabilir. Aşağıdaki kod, gelen isteği tek bir backend’e aktarır; ayrıca <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığıyla orijinal host bilgisini korur.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"log"</span>
    <span class="s">"net/http"</span>
    <span class="s">"net/http/httputil"</span>
    <span class="s">"net/url"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">target</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">url</span><span class="o">.</span><span class="n">Parse</span><span class="p">(</span><span class="s">"http://localhost:8081"</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="n">proxy</span> <span class="o">:=</span> <span class="n">httputil</span><span class="o">.</span><span class="n">NewSingleHostReverseProxy</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>

    <span class="n">originalDirector</span> <span class="o">:=</span> <span class="n">proxy</span><span class="o">.</span><span class="n">Director</span>
    <span class="n">proxy</span><span class="o">.</span><span class="n">Director</span> <span class="o">=</span> <span class="k">func</span><span class="p">(</span><span class="n">req</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">originalDirector</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>
        <span class="n">req</span><span class="o">.</span><span class="n">Header</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"X-Forwarded-Host"</span><span class="p">,</span> <span class="n">req</span><span class="o">.</span><span class="n">Host</span><span class="p">)</span>
        <span class="n">req</span><span class="o">.</span><span class="n">Header</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"X-Gateway"</span><span class="p">,</span> <span class="s">"go-reverse-proxy"</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Proxy :8080 üzerinde çalışıyor"</span><span class="p">)</span>
    <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="n">proxy</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">Director</code>, isteğin backend’e gitmeden önce nasıl değiştirileceğini belirler. Örneğin path yeniden yazılabilir, header eklenebilir veya belirli istekler engellenebilir. Pratikte burada kimlik doğrulama, IP filtreleme ya da rate limit kontrolü de uygulanabilir.</p>

<p>Şimdi bunu küçük bir round-robin yük dengeleyiciye çevirelim:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"log"</span>
    <span class="s">"net/http"</span>
    <span class="s">"net/http/httputil"</span>
    <span class="s">"net/url"</span>
    <span class="s">"sync/atomic"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Backend</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">URL</span>   <span class="o">*</span><span class="n">url</span><span class="o">.</span><span class="n">URL</span>
    <span class="n">Proxy</span> <span class="o">*</span><span class="n">httputil</span><span class="o">.</span><span class="n">ReverseProxy</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">LoadBalancer</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">backends</span> <span class="p">[]</span><span class="n">Backend</span>
    <span class="n">counter</span>  <span class="kt">uint64</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">lb</span> <span class="o">*</span><span class="n">LoadBalancer</span><span class="p">)</span> <span class="n">ServeHTTP</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">index</span> <span class="o">:=</span> <span class="n">atomic</span><span class="o">.</span><span class="n">AddUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lb</span><span class="o">.</span><span class="n">counter</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span> <span class="o">%</span> <span class="kt">uint64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">lb</span><span class="o">.</span><span class="n">backends</span><span class="p">))</span>
    <span class="n">backend</span> <span class="o">:=</span> <span class="n">lb</span><span class="o">.</span><span class="n">backends</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>
    <span class="n">r</span><span class="o">.</span><span class="n">Header</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"X-Selected-Backend"</span><span class="p">,</span> <span class="n">backend</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
    <span class="n">backend</span><span class="o">.</span><span class="n">Proxy</span><span class="o">.</span><span class="n">ServeHTTP</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">r</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">addresses</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
        <span class="s">"http://localhost:8081"</span><span class="p">,</span>
        <span class="s">"http://localhost:8082"</span><span class="p">,</span>
        <span class="s">"http://localhost:8083"</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="n">lb</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">LoadBalancer</span><span class="p">{}</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">addr</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">addresses</span> <span class="p">{</span>
        <span class="n">u</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">url</span><span class="o">.</span><span class="n">Parse</span><span class="p">(</span><span class="n">addr</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
            <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
        <span class="p">}</span>
        <span class="n">lb</span><span class="o">.</span><span class="n">backends</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">lb</span><span class="o">.</span><span class="n">backends</span><span class="p">,</span> <span class="n">Backend</span><span class="p">{</span>
            <span class="n">URL</span><span class="o">:</span>   <span class="n">u</span><span class="p">,</span>
            <span class="n">Proxy</span><span class="o">:</span> <span class="n">httputil</span><span class="o">.</span><span class="n">NewSingleHostReverseProxy</span><span class="p">(</span><span class="n">u</span><span class="p">),</span>
        <span class="p">})</span>
    <span class="p">}</span>

    <span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Load balancer :8080 üzerinde hazır"</span><span class="p">)</span>
    <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="n">lb</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">atomic.AddUint64</code>, eşzamanlı isteklerde sayaç yarışını engeller. Her istek farklı backend’e gönderilir. Matematiksel olarak seçim <code class="language-plaintext highlighter-rouge">index = counter \bmod n</code> şeklindedir. Yani sayaç büyür, backend listesi döngüsel biçimde kullanılır.</p>

<p>Güvenlik tarafında birkaç noktayı atlamamak gerekir. Proxy’niz dış dünyaya açık olduğu için header spoofing, yavaş istek saldırıları ve büyük body gönderimleriyle karşılaşabilir. <code class="language-plaintext highlighter-rouge">http.Server</code> yapılandırmasında timeout değerleri vermek iyi bir başlangıçtır.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">server</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">http</span><span class="o">.</span><span class="n">Server</span><span class="p">{</span>
    <span class="n">Addr</span><span class="o">:</span>              <span class="s">":8080"</span><span class="p">,</span>
    <span class="n">Handler</span><span class="o">:</span>           <span class="n">lb</span><span class="p">,</span>
    <span class="n">ReadHeaderTimeout</span><span class="o">:</span> <span class="m">5</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
    <span class="n">ReadTimeout</span><span class="o">:</span>       <span class="m">10</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
    <span class="n">WriteTimeout</span><span class="o">:</span>      <span class="m">15</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
    <span class="n">IdleTimeout</span><span class="o">:</span>       <span class="m">60</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Sonuç olarak Go, ters proxy yazmak için şaşırtıcı derecede güçlü bir araçtır. Küçük bir kod tabanıyla trafik yönlendirme, servis gizleme ve basit yük dengeleme yapabilirsiniz. Üretim ortamında buna health check, loglama, metrik toplama, TLS ve circuit breaker eklediğinizde kendi mini API gateway’inizi inşa etmiş olursunuz. Kısacası: Go ile ağ geçidi yazmak, hem öğretici hem de oldukça keyifli bir mühendislik egzersizidir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="go" /><category term="reverse-proxy" /><category term="load-balancing" /><category term="networking" /><summary type="html"><![CDATA[Modern web sistemlerinde istemci ile servisler arasına akıllı bir kapı koymak çoğu zaman hayat kurtarır. Go ile yazılmış hafif bir ters proxy, gelen HTTP trafiğini uygun backend servisine yönlendirebilir, temel güvenlik kontrolleri yapabilir ve yükü birden fazla sunucuya dağıtabilir. Üstelik Go’nun standart kütüphanesindeki net/http ve httputil paketleri sayesinde bunu devasa framework’lere ihtiyaç duymadan kurabilirsiniz.]]></summary></entry></feed>