Node.js İle Websocket Üzerinden Veri Akışı Nasıl Yapılır?

Node.js İle Websocket Üzerinden Veri Akışı Nasıl Yapılır?
Node.js İle Websocket Üzerinden Veri Akışı Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu projeye başlamadan önce bilgisayarınızda Node.js'in güncel bir sürümünün (en az v20.x veya v22.x LTS) kurulu olması gerekir. Ayrıca paket yönetimi için npm veya pnpm kullanacağız.

  • Node.js (LTS sürümü önerilir)
  • Bir kod editörü (VS Code tavsiye edilir)
  • Temel JavaScript (ES6+) bilgisi
  • Terminal veya komut satırı kullanımı

Projeyi başlatmak için bir klasör oluşturun ve gerekli kütüphaneleri yükleyin. Biz bu eğitimde en popüler ve performanslı kütüphanelerden biri olan ws kütüphanesini kullanacağız.

mkdir websocket-projesi
cd websocket-projesi
npm init -y
npm install ws

Yukarıdaki komutlar, projenizi başlatır ve Websocket iletişimini sağlayacak olan ws modülünü node_modules klasörüne ekler.

Adım Adım Websocket Sunucusu Kurulumu

Websocket sunucusu, istemcilerden gelen bağlantıları dinleyen ve bu bağlantılar üzerinden veri gönderip alan bir yapıdır. İlk adımda, basit bir sunucu ayağa kaldıracağız.

const { WebSocketServer } = require('ws');

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
    console.log('Yeni bir istemci bağlandı.');

    ws.on('message', (data) => {
        console.log('Alınan veri: %s', data);
        ws.send('Mesajınız sunucuya ulaştı: ' + data);
    });
});

console.log('Websocket sunucusu 8080 portunda çalışıyor.');

Bu kodda WebSocketServer sınıfını kullanarak 8080 portunda bir dinleyici oluşturduk. connection olayı, her yeni istemci bağlandığında tetiklenir. message olayı ise istemciden gelen verileri yakalamamızı sağlar.

İstemci Tarafında Bağlantı Nasıl Yapılır?

Sunucumuz hazır olduğuna göre, şimdi tarayıcı üzerinden bu sunucuya bağlanacak bir istemci oluşturalım. Tarayıcılar, yerel olarak WebSocket nesnesini destekler.

const socket = new WebSocket('ws://localhost:8080');

socket.onopen = () => {
    console.log('Sunucuya bağlandı!');
    socket.send('Merhaba Sunucu!');
};

socket.onmessage = (event) => {
    console.log('Sunucudan gelen: ', event.data);
};

Bu kod bloğu, tarayıcı konsolunda çalıştırıldığında sunucuya bir bağlantı isteği gönderir. Bağlantı açıldığında onopen tetiklenir ve sunucuya bir mesaj gönderilir. Sunucudan gelen yanıt ise onmessage ile yakalanır.

Veri Akışı Yönetimi ve Yayınlama (Broadcasting)

Gerçek dünya uygulamalarında, bir istemciden gelen verinin diğer tüm bağlı istemcilere gönderilmesi gerekebilir. Buna "broadcast" veya yayınlama denir.

wss.on('connection', (ws) => {
    ws.on('message', (data) => {
        wss.clients.forEach((client) => {
            if (client.readyState === 1) { // 1: OPEN durumu
                client.send(data.toString());
            }
        });
    });
});

Burada wss.clients dizisi üzerinden tüm bağlı istemcileri döngüye alıyoruz. readyState kontrolü, istemcinin hala bağlı olup olmadığını doğrulamak için kritik bir güvenlik ve performans önlemidir.

Websocket İletişim Yöntemlerinin Karşılaştırılması

Websocket dışında veri akışı için kullanılan diğer yöntemlerle bir kıyaslama yapalım:

Yöntem Avantaj Dezavantaj
Websocket Çift yönlü, çok hızlı Bağlantı yönetimi karmaşık
Polling Basit, HTTP tabanlı Sunucuya sürekli yük bindirir
Server-Sent Events Tek yönlü, kolay Sadece sunucudan istemciye

Güvenlik ve Üretim Ortamı İpuçları

Kritik Uyarı: Websocket bağlantılarında XSS (Cross-Site Scripting) saldırılarına karşı gelen veriyi her zaman doğrulayın ve temizleyin. Ayrıca, üretim ortamında (production) mutlaka wss:// (SSL/TLS) protokolünü kullanın. Ham veriyi asla doğrudan veritabanına veya HTML içine yerleştirmeyin.

Bağlantıların güvenliğini sağlamak için verifyClient özelliğini kullanarak bağlantı isteği sırasında kimlik doğrulama yapabilirsiniz.

const wss = new WebSocketServer({
    port: 8080,
    verifyClient: (info, cb) => {
        const token = info.req.headers['sec-websocket-protocol'];
        if (token === 'gizli-anahtar') {
            cb(true);
        } else {
            cb(false, 401, 'Unauthorized');
        }
    }
});

Hata Yönetimi ve Debug İpuçları

Websocket uygulamalarında en sık karşılaşılan sorun bağlantı kopmalarıdır. Bağlantının koptuğunu anlamak için heartbeat (kalp atışı) mekanizması kurmalısınız.

function heartbeat() {
    this.isAlive = true;
}

wss.on('connection', (ws) => {
    ws.isAlive = true;
    ws.on('pong', heartbeat);
});

setInterval(() => {
    wss.clients.forEach((ws) => {
        if (ws.isAlive === false) return ws.terminate();
        ws.isAlive = false;
        ws.ping();
    });
}, 30000);

Bu yapı, her 30 saniyede bir istemcilere "ping" atar. Yanıt gelmeyen bağlantıları terminate() ile sonlandırarak sunucu kaynaklarını koruruz.

Sıkça Sorulan Sorular

Websocket bağlantısı neden sürekli kopuyor?

Genellikle yük dengeleyiciler (load balancer) veya proxy sunucuları, boşta kalan TCP bağlantılarını kapatır. Yukarıda gösterilen "heartbeat" mekanizmasını kullanarak bağlantıyı canlı tutabilirsiniz.

Websocket ile dosya gönderilebilir mi?

Evet, ancak veriyi Buffer veya Blob formatına çevirmeniz gerekir. Büyük dosyalar için doğrudan Websocket yerine HTTP üzerinden yükleme yapıp, Websocket ile sadece dosya yolunu göndermek daha performanslıdır.

Aynı anda kaç bağlantı destekler?

Node.js'in tek iş parçacıklı yapısı göz önüne alındığında, donanımınıza bağlı olarak binlerce eşzamanlı bağlantıyı yönetebilirsiniz. Ancak mesaj trafiği arttıkça CPU kullanımı artacaktır.

Websocket güvenli mi?

HTTPS/WSS kullanıldığı sürece veriler şifrelenir. Ancak gelen verinin içeriği her zaman doğrulanmalıdır (Input Validation).

Socket.io kullanmalı mıyım?

Eğer otomatik yeniden bağlanma, oda (room) yapısı ve geniş çaplı tarayıcı desteği istiyorsanız Socket.io kullanmak işinizi kolaylaştırır. Ancak saf performans ve düşük bağımlılık istiyorsanız ws kütüphanesi daha uygundur.

Websocket Sunucularını Ölçeklendirme: Redis Pub/Sub Entegrasyonu

Tek bir sunucu üzerinde çalışan Websocket uygulamaları, kullanıcı sayısı arttıkça darboğaz yaşamaya başlar. Node.js tek iş parçacıklı (single-threaded) yapısı gereği CPU yoğun işlemlerde kısıtlı kalabilir. Çoklu sunucu (multi-instance) mimarisine geçtiğinizde, bir sunucuya bağlı olan istemcinin diğer sunucuya bağlı olan istemciye mesaj göndermesi imkansız hale gelir. Bu sorunu çözmek için Redis Pub/Sub mekanizması kullanılır.

Redis, sunucular arasında bir "mesaj otobüsü" görevi görür. Bir sunucuya gelen mesaj, Redis'e yayınlanır (publish) ve diğer tüm sunucular bu mesajı dinleyerek (subscribe) kendi bağlı oldukları istemcilere iletir.

// Redis ile mesaj yayınlama örneği
const redis = require('redis');
const publisher = redis.createClient();

function broadcastToAllServers(message) {
  publisher.publish('ws_channel', JSON.stringify(message));
}

// Tüm sunucularda çalışan dinleyici
const subscriber = redis.createClient();
subscriber.subscribe('ws_channel');

subscriber.on('message', (channel, message) => {
  const data = JSON.parse(message);
  // Tüm bağlı istemcilere veriyi gönder
  wss.clients.forEach(client => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(JSON.stringify(data));
    }
  });
});

Websocket Performansını İzleme ve Optimizasyon

Gerçek zamanlı uygulamalarda gecikme (latency) en büyük düşmandır. Websocket bağlantılarınızın sağlığını takip etmek için bazı metrikleri izlemeniz gerekir. Özellikle "Heartbeat" mekanizması, bağlantıların canlı kalmasını sağlarken gereksiz kaynak tüketimini de engeller.

Bağlantı Sağlığını İzleme

Bağlantıların kopup kopmadığını anlamak için periyodik olarak "ping" paketleri gönderilmelidir. Eğer istemci belirli bir süre içinde "pong" yanıtı dönmezse, bağlantı sonlandırılmalıdır.

// Sunucu tarafında basit bir heartbeat kontrolü
function heartbeat() {
  this.isAlive = true;
}

wss.on('connection', (ws) => {
  ws.isAlive = true;
  ws.on('pong', heartbeat);
});

const interval = setInterval(() => {
  wss.clients.forEach((ws) => {
    if (ws.isAlive === false) return ws.terminate();
    
    ws.isAlive = false;
    ws.ping();
  });
}, 30000); // 30 saniyede bir kontrol et

Performans İpuçları

  • Veri Sıkıştırma: Çok büyük JSON verileri gönderiyorsanız, perMessageDeflate özelliğini kullanarak ağ trafiğini azaltabilirsiniz.
  • Binary Veri Kullanımı: Mümkünse metin (JSON) yerine Buffer veya ArrayBuffer kullanarak veri boyutunu küçültün.
  • Olay Döngüsünü Korumak: Websocket mesaj işleyicilerinde ağır senkron işlemler (dosya okuma, karmaşık döngüler) yapmaktan kaçının; bu, tüm sunucunun yanıt vermesini durdurabilir.
  • Yük Dengeleyici (Load Balancer) Yapılandırması: Nginx veya HAProxy kullanırken Upgrade başlıklarının düzgün iletildiğinden ve "sticky session" (oturum sürekliliği) ayarlarının aktif olduğundan emin olun.

Bu optimizasyonlar, uygulamanızın binlerce eşzamanlı bağlantıyı düşük gecikme süresiyle yönetmesine olanak tanır. Özellikle yüksek trafikli canlı sohbet veya borsa verisi uygulamalarında bu mimari standart kabul edilir.

Sonuç

Node.js ile Websocket kullanarak gerçek zamanlı veri akışı sağlamak, doğru kütüphane ve güvenlik önlemleriyle oldukça güçlü bir araçtır. Bu rehberde temel sunucu kurulumundan, veri yayınlamaya ve bağlantı güvenliğine kadar kritik adımları tamamladınız. Bir sonraki adım olarak, Redis kullanarak bu Websocket sunucusunu ölçeklenebilir (scalable) hale getirmeyi veya Socket.io kütüphanesini inceleyerek daha karmaşık oda yapılarını öğrenmeyi deneyebilirsiniz.

Yasal Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında kullanmadan önce güvenlik açıklarını (SQL injection, XSS vb.) göz önünde bulundurarak profesyonel güvenlik testlerinden geçirmeniz önerilir.

Bu yazıya tepkinizi paylaşın:
Kerem Tekin

Teknik rehberler ve dijital araçların verimli kullanımı konusunda uzmanlaşmış bir editörüm. Karmaşık teknolojik süreçleri, herkesin kolayca uygulayabileceği rehberlere dönüştürerek zaman tasarrufu sağlamayı hedefliyorum.

Yorumlar (0)

Yorum Yaz