<?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-15T10:35:19+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 Gömülü Sistemlerde Bellek Yönetimi: Her Byte’ın Hesabını Tutmak</title><link href="https://sonsuzus.github.io/posts/c-ile-gomulu-sistemlerde-bellek-yonetimi-her-bytein-hesabini-tutmak/" rel="alternate" type="text/html" title="C ile Gömülü Sistemlerde Bellek Yönetimi: Her Byte’ın Hesabını Tutmak" /><published>2026-07-15T00:00:00+00:00</published><updated>2026-07-15T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-gomulu-sistemlerde-bellek-yonetimi-her-bytein-hesabini-tutmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-gomulu-sistemlerde-bellek-yonetimi-her-bytein-hesabini-tutmak/"><![CDATA[<p>Gömülü sistemlerde bellek yönetimi, masaüstü programlamadaki konforlu dünyadan biraz farklıdır: burada RAM bazen birkaç kilobayttır, heap kullanmak riskli olabilir ve yanlış boyutlandırılmış bir dizi tüm kontrol döngüsünü sabote edebilir. C dili bu dünyada hâlâ kraldır; çünkü donanıma yakın çalışır, maliyeti düşüktür ve geliştiriciye her byte üzerinde doğrudan kontrol verir.
``
Bir mikrodenetleyicide bellek genellikle üç ana bölge gibi düşünülür: Flash, RAM ve çevresel register alanları. Flash program kodunu ve sabit verileri tutar; RAM ise çalışma zamanındaki değişkenler, stack ve varsa heap için kullanılır. Kısıtlı sistemlerde temel denklem şudur: $RAM_{kalan} = RAM_{toplam} - (global + stack + heap + buffer)$. Bu denklem basit görünür ama gerçek hayatta her kesme rutini, her geçici değişken ve her iletişim tamponu bu hesabı değiştirir.</p>

<table>
  <thead>
    <tr>
      <th>Bellek Alanı</th>
      <th>Ne İçin Kullanılır?</th>
      <th>Avantaj</th>
      <th>Risk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Flash</td>
      <td>Kod, sabit tablolar</td>
      <td>RAM tüketmez</td>
      <td>Yazma yavaştır, sınırlı ömür</td>
    </tr>
    <tr>
      <td>Global/Static RAM</td>
      <td>Kalıcı değişkenler</td>
      <td>Öngörülebilir</td>
      <td>Fazla kullanılırsa RAM biter</td>
    </tr>
    <tr>
      <td>Stack</td>
      <td>Fonksiyon çağrıları, yerel değişkenler</td>
      <td>Hızlı</td>
      <td>Taşma tespiti zordur</td>
    </tr>
    <tr>
      <td>Heap</td>
      <td>Dinamik ayırma</td>
      <td>Esnek</td>
      <td>Parçalanma ve belirsizlik</td>
    </tr>
  </tbody>
</table>

<p>Kontrol döngülerinde hedef yalnızca az bellek kullanmak değildir; aynı zamanda zamanlamayı da garanti etmektir. Örneğin bir motor kontrol döngüsünde örnekleme süresi $T_s = 1ms$ ise, bellek ayırma yüzünden oluşan rastgele gecikmeler kabul edilemez. Bu yüzden gömülü C projelerinde <code class="language-plaintext highlighter-rouge">malloc</code> ve <code class="language-plaintext highlighter-rouge">free</code> çoğu zaman yasaklı kelimeler gibidir. Heap parçalanması, başlangıçta çalışıp saatler sonra çöken cihazların klasik sebeplerindendir.</p>

<p>Dinamik ayırma gerekiyorsa, genel amaçlı heap yerine sabit bloklu bir bellek havuzu daha güvenlidir. Aşağıdaki örnek, 16 adet sabit boyutlu mesaj bloğunu yönetir. Böylece ayırma süresi yaklaşık sabittir ve parçalanma oluşmaz.</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">
#include</span> <span class="cpf">&lt;stddef.h&gt;</span><span class="cp">
</span>
<span class="cp">#define BLOCK_SIZE 32
#define BLOCK_COUNT 16
</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">data</span><span class="p">[</span><span class="n">BLOCK_SIZE</span><span class="p">];</span>
    <span class="kt">uint8_t</span> <span class="n">used</span><span class="p">;</span>
<span class="p">}</span> <span class="n">Block</span><span class="p">;</span>

<span class="k">static</span> <span class="n">Block</span> <span class="n">pool</span><span class="p">[</span><span class="n">BLOCK_COUNT</span><span class="p">];</span>

<span class="kt">void</span> <span class="o">*</span><span class="nf">pool_alloc</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">uint8_t</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">BLOCK_COUNT</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">used</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">used</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
            <span class="k">return</span> <span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">data</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">pool_free</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">uint8_t</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">BLOCK_COUNT</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">used</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu kodda belleğin tamamı derleme zamanında ayrılır. <code class="language-plaintext highlighter-rouge">pool_alloc</code>, boş bir blok bulur ve işaretçi döndürür. <code class="language-plaintext highlighter-rouge">pool_free</code> ise bloğu tekrar kullanılabilir hâle getirir. Dezavantajı, her bloğun aynı boyutta olmasıdır; 5 byte veriye de 32 byte ayrılır. Ancak gömülü sistemlerde öngörülebilirlik çoğu zaman maksimum verimden daha değerlidir.</p>

<p>Stack kullanımı da ayrıca izlenmelidir. Büyük dizileri fonksiyon içinde tanımlamak cazip görünür ama tehlikelidir. Örneğin <code class="language-plaintext highlighter-rouge">uint8_t buffer[1024];</code> satırı, 2 KB RAM bulunan bir mikrodenetleyicide felaketin yarısı olabilir. Büyük tamponlar global veya static tanımlanmalı, mümkünse boyutları hesaplanmalıdır: \(Buffer_{toplam}=N_{paket}\times Boyut_{paket}\). Eğer UART üzerinden 8 paket tutulacak ve her paket 32 byte olacaksa toplam tampon 256 byte eder; kulağa az gelir ama 2 KB RAM içinde yüzde 12.5 demektir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Ne Zaman Tercih Edilir?</th>
      <th>Bellek Davranışı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Yerel küçük değişken</td>
      <td>Kısa hesaplamalar</td>
      <td>Stack üzerinde hızlı</td>
    </tr>
    <tr>
      <td>Static tampon</td>
      <td>Sürekli kullanılan veri</td>
      <td>Sabit RAM tüketimi</td>
    </tr>
    <tr>
      <td>Ring buffer</td>
      <td>UART, ADC, sensör akışı</td>
      <td>Verimli ve tahmin edilebilir</td>
    </tr>
    <tr>
      <td>Heap</td>
      <td>Nadiren önerilir</td>
      <td>Esnek ama riskli</td>
    </tr>
  </tbody>
</table>

<p>Veri tipi seçimi de byte avcılığının eğlenceli kısmıdır. Sıcaklık 0-100 arasıysa <code class="language-plaintext highlighter-rouge">uint8_t</code> yeterli olabilir; sayaç 100000 değerine çıkacaksa <code class="language-plaintext highlighter-rouge">uint32_t</code> gerekir. Ancak işlemci 8 bit ise 32 bit aritmetik daha yavaş olabilir. Yani bellek optimizasyonu ile CPU maliyeti birlikte düşünülmelidir.</p>

<p>Pratikte iyi bir strateji şudur: önce bellek haritasını çıkar, global değişkenleri say, maksimum stack derinliğini tahmin et, kesme rutinlerinde büyük işlem yapma ve iletişim tamponlarını matematiksel olarak boyutlandır. Derleyicinin map dosyası bu noktada hazine haritasıdır; hangi sembolün kaç byte tuttuğunu gösterir.</p>

<p>Sonuç olarak C ile gömülü sistemlerde bellek yönetimi, biraz muhasebe biraz da mühendislik sezgisidir. Her byte’ın bir görevi olmalı, her tamponun nedeni bilinmeli ve her kontrol döngüsü zamanında bitmelidir. Kaynak kısıtlı olabilir; ama iyi tasarlanmış bir bellek düzeniyle küçük bir mikrodenetleyici bile şaşırtıcı derecede kararlı ve güçlü çalışabilir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="C" /><category term="Gömülü Sistemler" /><category term="Bellek Yönetimi" /><category term="Mikrodenetleyici" /><summary type="html"><![CDATA[Gömülü sistemlerde bellek yönetimi, masaüstü programlamadaki konforlu dünyadan biraz farklıdır: burada RAM bazen birkaç kilobayttır, heap kullanmak riskli olabilir ve yanlış boyutlandırılmış bir dizi tüm kontrol döngüsünü sabote edebilir. C dili bu dünyada hâlâ kraldır; çünkü donanıma yakın çalışır, maliyeti düşüktür ve geliştiriciye her byte üzerinde doğrudan kontrol verir.]]></summary></entry><entry><title type="html">JavaScript ile Mantık Bulmacaları Çözücüleri: Tarayıcıda Adım Adım Algoritma Şovu</title><link href="https://sonsuzus.github.io/posts/javascript-ile-mantik-bulmacalari-cozuculeri-tarayicida-adim-adim-algoritma-sovu/" rel="alternate" type="text/html" title="JavaScript ile Mantık Bulmacaları Çözücüleri: Tarayıcıda Adım Adım Algoritma Şovu" /><published>2026-07-15T00:00:00+00:00</published><updated>2026-07-15T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/javascript-ile-mantik-bulmacalari-cozuculeri-tarayicida-adim-adim-algoritma-sovu</id><content type="html" xml:base="https://sonsuzus.github.io/posts/javascript-ile-mantik-bulmacalari-cozuculeri-tarayicida-adim-adim-algoritma-sovu/"><![CDATA[<p>Bir Sudoku karesine bakıp beyninizin fanlarının hızlandığını hissettiyseniz, yalnız değilsiniz. Güzel haber şu: JavaScript ile tarayıcı üzerinde çalışan, hem bulmacayı çözen hem de çözüm adımlarını görselleştiren etkileşimli çözücüler yazabiliriz. Bu yazıda mantık bulmacalarını sadece kodla çözmeyi değil, algoritmanın nasıl düşündüğünü kullanıcıya sahne sahne göstermeyi konuşacağız.
``</p>

<h2 id="bulmaca-çözmek-aslında-arama-problemidir">Bulmaca çözmek aslında arama problemidir</h2>

<p>Birçok mantık bulmacası, bilgisayar bilimi açısından bir <strong>durum uzayı araması</strong> problemidir. Elimizde başlangıç durumu, geçerli hamle kuralları ve hedef durum vardır. Örneğin Sudoku için hedef, her satırda, sütunda ve 3x3 kutuda 1’den 9’a kadar sayıların çakışmadan yerleşmesidir.</p>

<p>Teorik olarak her boş hücre için olasılıkları deneriz. Eğer $b$ her adımda ortalama seçenek sayısı, $d$ ise boş hücre sayısıysa kaba karmaşıklık $O(b^d)$ olur. Kulağa korkutucu geliyor; çünkü gerçekten de öyle. Ama kısıtlar ve akıllı seçim stratejileriyle arama ağacını ciddi biçimde budayabiliriz.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Mantık</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Brute force</td>
      <td>Tüm olasılıkları dener</td>
      <td>Basit uygulanır</td>
      <td>Çok yavaş olabilir</td>
    </tr>
    <tr>
      <td>Backtracking</td>
      <td>Hatalı yolda geri döner</td>
      <td>Pratik ve anlaşılır</td>
      <td>Kötü seçimlerde dallanır</td>
    </tr>
    <tr>
      <td>Constraint propagation</td>
      <td>İmkansız seçenekleri erken eler</td>
      <td>Çok hızlandırır</td>
      <td>Kuralları modellemek gerekir</td>
    </tr>
    <tr>
      <td>Heuristic seçim</td>
      <td>En az seçenekli hücreyi seçer</td>
      <td>Aramayı küçültür</td>
      <td>Ek hesaplama ister</td>
    </tr>
  </tbody>
</table>

<h2 id="tarayıcı-neden-harika-bir-oyun-alanı">Tarayıcı neden harika bir oyun alanı?</h2>

<p>Tarayıcı bize üç güzel şey verir: DOM ile görsel arayüz, Canvas/SVG ile çizim ve <code class="language-plaintext highlighter-rouge">async/await</code> ile adım adım animasyon. Böylece algoritma sadece sonucu basmaz; hangi hücreyi denediğini, nerede çuvalladığını ve neden geri döndüğünü de gösterir. Kullanıcı için bu, kara kutu yerine cam kutu deneyimidir.</p>

<p>Aşağıdaki örnek, basitleştirilmiş bir Sudoku çözücünün kalbini gösterir. Amaç, boş hücre bulmak, geçerli sayıları denemek ve çıkmaz sokakta geri almaktır.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">findEmpty</span><span class="p">(</span><span class="nx">board</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">r</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">r</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">r</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">c</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">c</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if </span><span class="p">(</span><span class="nx">board</span><span class="p">[</span><span class="nx">r</span><span class="p">][</span><span class="nx">c</span><span class="p">]</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="p">{</span> <span class="nx">r</span><span class="p">,</span> <span class="nx">c</span> <span class="p">};</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">isValid</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">r</span><span class="p">,</span> <span class="nx">c</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">board</span><span class="p">[</span><span class="nx">r</span><span class="p">][</span><span class="nx">i</span><span class="p">]</span> <span class="o">===</span> <span class="nx">n</span> <span class="o">||</span> <span class="nx">board</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="nx">c</span><span class="p">]</span> <span class="o">===</span> <span class="nx">n</span><span class="p">)</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">const</span> <span class="nx">sr</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="nx">r</span> <span class="o">/</span> <span class="mi">3</span><span class="p">)</span> <span class="o">*</span> <span class="mi">3</span><span class="p">;</span>
  <span class="kd">const</span> <span class="nx">sc</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="nx">c</span> <span class="o">/</span> <span class="mi">3</span><span class="p">)</span> <span class="o">*</span> <span class="mi">3</span><span class="p">;</span>

  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">sr</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">sr</span> <span class="o">+</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">j</span> <span class="o">=</span> <span class="nx">sc</span><span class="p">;</span> <span class="nx">j</span> <span class="o">&lt;</span> <span class="nx">sc</span> <span class="o">+</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if </span><span class="p">(</span><span class="nx">board</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="nx">j</span><span class="p">]</span> <span class="o">===</span> <span class="nx">n</span><span class="p">)</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu iki fonksiyon hakem gibi çalışır. <code class="language-plaintext highlighter-rouge">findEmpty</code>, sıradaki problemi bulur; <code class="language-plaintext highlighter-rouge">isValid</code> ise önerilen hamlenin kurallara uygun olup olmadığını söyler. Şimdi buna görsellik ekleyelim.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">sleep</span> <span class="o">=</span> <span class="nx">ms</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nc">Promise</span><span class="p">(</span><span class="nx">resolve</span> <span class="o">=&gt;</span> <span class="nf">setTimeout</span><span class="p">(</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">ms</span><span class="p">));</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nf">solve</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">render</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">cell</span> <span class="o">=</span> <span class="nf">findEmpty</span><span class="p">(</span><span class="nx">board</span><span class="p">);</span>
  <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">cell</span><span class="p">)</span> <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>

  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">n</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">n</span> <span class="o">&lt;=</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">n</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if </span><span class="p">(</span><span class="nf">isValid</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">cell</span><span class="p">.</span><span class="nx">r</span><span class="p">,</span> <span class="nx">cell</span><span class="p">.</span><span class="nx">c</span><span class="p">,</span> <span class="nx">n</span><span class="p">))</span> <span class="p">{</span>
      <span class="nx">board</span><span class="p">[</span><span class="nx">cell</span><span class="p">.</span><span class="nx">r</span><span class="p">][</span><span class="nx">cell</span><span class="p">.</span><span class="nx">c</span><span class="p">]</span> <span class="o">=</span> <span class="nx">n</span><span class="p">;</span>
      <span class="nf">render</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">cell</span><span class="p">,</span> <span class="dl">'</span><span class="s1">try</span><span class="dl">'</span><span class="p">);</span>
      <span class="k">await</span> <span class="nf">sleep</span><span class="p">(</span><span class="mi">80</span><span class="p">);</span>

      <span class="k">if </span><span class="p">(</span><span class="k">await</span> <span class="nf">solve</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">render</span><span class="p">))</span> <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>

      <span class="nx">board</span><span class="p">[</span><span class="nx">cell</span><span class="p">.</span><span class="nx">r</span><span class="p">][</span><span class="nx">cell</span><span class="p">.</span><span class="nx">c</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="nf">render</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">cell</span><span class="p">,</span> <span class="dl">'</span><span class="s1">backtrack</span><span class="dl">'</span><span class="p">);</span>
      <span class="k">await</span> <span class="nf">sleep</span><span class="p">(</span><span class="mi">80</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">render</code> fonksiyonu arayüzü günceller. <code class="language-plaintext highlighter-rouge">try</code> durumunda hücre yeşil, <code class="language-plaintext highlighter-rouge">backtrack</code> durumunda kırmızı gösterilebilir. Böylece kullanıcı algoritmanın düşündüğü yolları izler.</p>

<h2 id="daha-zeki-çözücü-en-az-adaylı-hücre">Daha zeki çözücü: en az adaylı hücre</h2>

<p>Sıradaki boş hücreyi soldan sağa seçmek kolaydır ama her zaman akıllıca değildir. Daha iyi strateji, aday sayısı en az olan hücreyi seçmektir. Buna genellikle <strong>MRV</strong>, yani minimum remaining values denir. Eğer bir hücrede sadece 2 ihtimal, diğerinde 7 ihtimal varsa önce 2 ihtimalli hücreye bakmak mantıklıdır.</p>

<p>Bu yaklaşım arama ağacını küçültür. Örneğin teorik olarak $5^{40}$ gibi devasa bir deneme alanı, iyi kısıtlarla çok daha yönetilebilir hale gelir. Elbette garanti sihir değildir; fakat gerçek bulmacalarda fark şaşırtıcıdır.</p>

<h2 id="görsel-bulmacalara-genişletmek">Görsel bulmacalara genişletmek</h2>

<p>Aynı model Sudoku dışında Nonogram, KenKen, labirent, taş kaydırma oyunları ve hatta satranç problemleri için kullanılabilir. Değişen şey <code class="language-plaintext highlighter-rouge">isValid</code> fonksiyonunun kurallarıdır. Nonogram’da satır ipuçlarını, labirentte duvarları, satrançta taş hareketlerini kontrol edersiniz. Genel iskelet aynı kalır: durum üret, geçerliliği kontrol et, uygunsa ilerle, değilse geri dön.</p>

<h2 id="son-dokunuşlar">Son dokunuşlar</h2>

<p>Kullanıcıya hız kontrolü, adım sayacı, duraklat-devam et düğmesi ve çözüm geçmişi eklerseniz proje bir algoritma demosundan mini eğitim aracına dönüşür. Hatta her hamleyi bir listeye yazıp neden seçildiğini açıklayabilirsiniz. İşin eğlenceli tarafı şu: JavaScript burada yalnızca çözüm üreten bir araç değil, algoritmanın zihnini görünür kılan bir sahne yönetmenidir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="javascript" /><category term="algoritma" /><category term="bulmaca" /><category term="backtracking" /><category term="web" /><summary type="html"><![CDATA[Bir Sudoku karesine bakıp beyninizin fanlarının hızlandığını hissettiyseniz, yalnız değilsiniz. Güzel haber şu: JavaScript ile tarayıcı üzerinde çalışan, hem bulmacayı çözen hem de çözüm adımlarını görselleştiren etkileşimli çözücüler yazabiliriz. Bu yazıda mantık bulmacalarını sadece kodla çözmeyi değil, algoritmanın nasıl düşündüğünü kullanıcıya sahne sahne göstermeyi konuşacağız.]]></summary></entry><entry><title type="html">Python ile Webhook Entegrasyonları: Sosyal Medyadan Otomatik Konu Açma</title><link href="https://sonsuzus.github.io/posts/python-ile-webhook-entegrasyonlari-sosyal-medyadan-otomatik-konu-acma/" rel="alternate" type="text/html" title="Python ile Webhook Entegrasyonları: Sosyal Medyadan Otomatik Konu Açma" /><published>2026-07-15T00:00:00+00:00</published><updated>2026-07-15T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/python-ile-webhook-entegrasyonlari-sosyal-medyadan-otomatik-konu-acma</id><content type="html" xml:base="https://sonsuzus.github.io/posts/python-ile-webhook-entegrasyonlari-sosyal-medyadan-otomatik-konu-acma/"><![CDATA[<p>Sosyal medyada biri markanızdan bahsettiğinde, yeni bir gönderi paylaştığında veya belirli bir etiketi kullandığında başka bir sitede otomatik konu açıldığını düşünün. İşte webhook entegrasyonları tam olarak bu küçük dijital domino taşlarını devirir: bir olay olur, Python dinler, doğrular, işler ve hedef sisteme aksiyon aldırır.
``
Webhook, klasik API sorgulamasının tersine çalışan bir bildirim mekanizmasıdır. Normalde siz API’ye sürekli “Yeni bir şey var mı?” diye sorarsınız; buna polling denir. Webhook’ta ise platform size “Bir şey oldu, al sana veri!” der. Bu yaklaşım hem daha hızlıdır hem de gereksiz istek trafiğini azaltır.</p>

<p>Basit akış şöyledir:</p>

<ol>
  <li>Sosyal medya platformunda olay gerçekleşir.</li>
  <li>Platform, sizin belirlediğiniz URL’ye HTTP POST isteği gönderir.</li>
  <li>Python uygulamanız imzayı ve veriyi doğrular.</li>
  <li>Olay türüne göre hedef sitede konu açılır.</li>
  <li>Sonuç loglanır, hata varsa tekrar deneme kuyruğuna alınır.</li>
</ol>

<p>Teorik olarak bir webhook sistemini şu fonksiyon gibi düşünebiliriz:</p>

\[f(event) = action\]

<p>Burada $event$ sosyal medya hareketini, $action$ ise başka sitede konu açma işlemini temsil eder. Ancak gerçek dünyada iş biraz daha baharatlıdır: güvenlik, tekrar eden istekler, zaman aşımı, API limitleri ve veri eşleme gibi konular devreye girer.</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>Polling</td>
      <td>Belirli aralıklarla API sorgulanır</td>
      <td>Kurulumu basit</td>
      <td>Gereksiz trafik ve gecikme</td>
    </tr>
    <tr>
      <td>Webhook</td>
      <td>Olay olunca platform size istek atar</td>
      <td>Anlık ve verimli</td>
      <td>Güvenlik ve erişilebilirlik ister</td>
    </tr>
    <tr>
      <td>Kuyruklu Webhook</td>
      <td>Olay kuyruğa alınır, sonra işlenir</td>
      <td>Dayanıklı ve ölçeklenebilir</td>
      <td>Ek altyapı gerekir</td>
    </tr>
  </tbody>
</table>

<p>Güvenlik tarafında en önemli noktalardan biri imza doğrulamadır. Platform genellikle gövde verisini gizli anahtarla imzalar. Siz de aynı hesabı yapıp gelen imzayla karşılaştırırsınız:</p>

\[signature = HMAC_{SHA256}(secret, payload)\]

<p>Eğer imzalar eşleşmiyorsa istek reddedilmelidir. Çünkü internete açık bir endpoint, robotların ve meraklı kişilerin favori oyun alanıdır.</p>

<p>Aşağıdaki örnek Flask ile yazılmış orta düzey bir webhook alıcısıdır. Gelen olayı doğrular, aynı olayın iki kez işlenmesini engeller ve hedef foruma konu açmak için örnek bir POST isteği gönderir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">os</span>
<span class="kn">import</span> <span class="n">hmac</span>
<span class="kn">import</span> <span class="n">hashlib</span>
<span class="kn">import</span> <span class="n">requests</span>
<span class="kn">from</span> <span class="n">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">abort</span><span class="p">,</span> <span class="n">jsonify</span>

<span class="n">app</span> <span class="o">=</span> <span class="nc">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>

<span class="n">SECRET</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">WEBHOOK_SECRET</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">dev-secret</span><span class="sh">'</span><span class="p">)</span>
<span class="n">FORUM_API</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">FORUM_API</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">https://forum.example.com/api/topics</span><span class="sh">'</span><span class="p">)</span>
<span class="n">FORUM_TOKEN</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">FORUM_TOKEN</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">demo-token</span><span class="sh">'</span><span class="p">)</span>

<span class="n">processed_events</span> <span class="o">=</span> <span class="nf">set</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">verify_signature</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">received_signature</span><span class="p">):</span>
    <span class="n">expected</span> <span class="o">=</span> <span class="n">hmac</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
        <span class="n">SECRET</span><span class="p">.</span><span class="nf">encode</span><span class="p">(),</span>
        <span class="n">payload</span><span class="p">,</span>
        <span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span>
    <span class="p">).</span><span class="nf">hexdigest</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">hmac</span><span class="p">.</span><span class="nf">compare_digest</span><span class="p">(</span><span class="n">expected</span><span class="p">,</span> <span class="n">received_signature</span> <span class="ow">or</span> <span class="sh">''</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">create_topic</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
    <span class="n">username</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">username</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">bilinmeyen</span><span class="sh">'</span><span class="p">)</span>
    <span class="n">text</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">text</span><span class="sh">'</span><span class="p">,</span> <span class="sh">''</span><span class="p">)</span>
    <span class="n">platform</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">platform</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">sosyal medya</span><span class="sh">'</span><span class="p">)</span>

    <span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
        <span class="sh">'</span><span class="s">title</span><span class="sh">'</span><span class="p">:</span> <span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">platform</span><span class="si">}</span><span class="s"> üzerinde yeni hareket: </span><span class="si">{</span><span class="n">username</span><span class="si">}</span><span class="sh">'</span><span class="p">,</span>
        <span class="sh">'</span><span class="s">body</span><span class="sh">'</span><span class="p">:</span> <span class="sa">f</span><span class="sh">'</span><span class="s">Kullanıcı: </span><span class="si">{</span><span class="n">username</span><span class="si">}</span><span class="se">\n\n</span><span class="s">İçerik:</span><span class="se">\n</span><span class="si">{</span><span class="n">text</span><span class="si">}</span><span class="sh">'</span><span class="p">,</span>
        <span class="sh">'</span><span class="s">category</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">Sosyal Medya</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">FORUM_TOKEN</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">post</span><span class="p">(</span><span class="n">FORUM_API</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="n">data</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">10</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="k">return</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>

<span class="nd">@app.post</span><span class="p">(</span><span class="sh">'</span><span class="s">/webhooks/social</span><span class="sh">'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">social_webhook</span><span class="p">():</span>
    <span class="n">payload</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">get_data</span><span class="p">()</span>
    <span class="n">signature</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">X-Signature</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="nf">verify_signature</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">signature</span><span class="p">):</span>
        <span class="nf">abort</span><span class="p">(</span><span class="mi">401</span><span class="p">)</span>

    <span class="n">event</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">get_json</span><span class="p">()</span>
    <span class="n">event_id</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">id</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">event_id</span> <span class="ow">in</span> <span class="n">processed_events</span><span class="p">:</span>
        <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">status</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">duplicate_ignored</span><span class="sh">'</span><span class="p">})</span>

    <span class="n">processed_events</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">event_id</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">type</span><span class="sh">'</span><span class="p">)</span> <span class="o">==</span> <span class="sh">'</span><span class="s">mention</span><span class="sh">'</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="nf">create_topic</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
        <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">status</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">topic_created</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">result</span><span class="sh">'</span><span class="p">:</span> <span class="n">result</span><span class="p">})</span>

    <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">status</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">ignored</span><span class="sh">'</span><span class="p">})</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">processed_events</code> örnek amaçlı bellekte tutuluyor. Gerçek projede Redis, PostgreSQL veya benzeri kalıcı bir sistem kullanmak daha doğrudur. Çünkü uygulama yeniden başlarsa bellek sıfırlanır ve aynı olay tekrar konu açabilir. Bu probleme idempotency denir: aynı isteğin birden fazla kez gelmesi durumunda sistemin aynı sonucu üretmesi gerekir.</p>

<p>Veri eşleme de önemlidir. Sosyal medya olayı doğrudan forum konusuna dönüşmez; arada anlamlı bir çeviri katmanı gerekir.</p>

<table>
  <thead>
    <tr>
      <th>Webhook Alanı</th>
      <th>Forum Alanı</th>
      <th>Dönüşüm Mantığı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">username</code></td>
      <td>Konu başlığı</td>
      <td>Hareketi yapan kişiyi belirtir</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">text</code></td>
      <td>Konu içeriği</td>
      <td>Paylaşım veya yorum metni eklenir</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">platform</code></td>
      <td>Etiket</td>
      <td>Kaynağın neresi olduğu anlaşılır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">created_at</code></td>
      <td>Zaman bilgisi</td>
      <td>Konunun bağlamını güçlendirir</td>
    </tr>
  </tbody>
</table>

<p>Hata yönetimi tarafında üstel geri çekilme kullanabilirsiniz. Örneğin tekrar deneme süresi şu şekilde büyüyebilir:</p>

\[delay = min(2^n, 300)\]

<p>Burada $n$ deneme sayısıdır, üst sınır ise 300 saniyedir. Böylece hedef site kısa süreli çökerse sisteminiz panikle spam atmaz.</p>

<p>Sonuç olarak Python ile webhook entegrasyonu, sadece bir endpoint yazmaktan ibaret değildir. Güvenli doğrulama, idempotency, veri dönüştürme, loglama ve tekrar deneme stratejileriyle birleşince ortaya sosyal medya hareketlerini otomatik aksiyona dönüştüren sağlam bir tetikleyici mekanizma çıkar. Küçük başlar, sonra bir bakmışsınız forumunuz sosyal medyanın nabzını gerçek zamanlı tutan mini bir haber merkezine dönüşmüş!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="python" /><category term="webhook" /><category term="otomasyon" /><category term="api" /><summary type="html"><![CDATA[Sosyal medyada biri markanızdan bahsettiğinde, yeni bir gönderi paylaştığında veya belirli bir etiketi kullandığında başka bir sitede otomatik konu açıldığını düşünün. İşte webhook entegrasyonları tam olarak bu küçük dijital domino taşlarını devirir: bir olay olur, Python dinler, doğrular, işler ve hedef sisteme aksiyon aldırır.]]></summary></entry><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></feed>