Gereksinimler ve Ön Hazırlık
Projeye başlamadan önce sisteminizde Node.js'in 20.x veya daha güncel bir sürümünün kurulu olduğundan emin olun. Geliştirme ortamınızda terminali açarak node -v komutu ile sürüm kontrolü yapabilirsiniz. Bu rehberde paket yöneticisi olarak npm kullanılacaktır.
Proje dizinini oluşturun ve gerekli bağımlılıkları yükleyin:
mkdir bildirim-servisi
cd bildirim-servisi
npm init -y
npm install express socket.io cors
Burada kullandığımız express web sunucusu çatısını, socket.io gerçek zamanlı iletişim kütüphanesini ve cors ise farklı kaynaklardan gelen istekleri yönetmek için gerekli olan güvenlik katmanını temsil eder.
Sunucu Tarafı Kurulumu ve Socket.io Entegrasyonu
Websocket bağlantısını başlatmak için öncelikle bir HTTP sunucusu oluşturmalı ve bu sunucuyu Socket.io ile sarmalamalıyız. Bu yapı, standart HTTP istekleri ile Websocket bağlantılarının aynı port üzerinden yönetilmesine olanak tanır.
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const cors = require('cors');
const app = express();
app.use(cors());
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "*", // Üretim ortamında burayı kendi domaininizle sınırlayın
methods: ["GET", "POST"]
}
});
io.on('connection', (socket) => {
console.log('Yeni bir kullanıcı bağlandı: ', socket.id);
socket.on('disconnect', () => {
console.log('Kullanıcı ayrıldı');
});
});
server.listen(3000, () => {
console.log('Sunucu 3000 portunda çalışıyor.');
});
Bu kod bloğu, temel bir sunucu çatısı oluşturur. io.on('connection') fonksiyonu, her yeni bağlantı kurulduğunda tetiklenir ve istemciye özel bir socket nesnesi döndürür.
İstemci Tarafında Bildirim Alma
Sunucu tarafındaki bildirimleri tarayıcıda karşılamak için Socket.io istemci kütüphanesini kullanmalıyız. İstemci, sunucuya bağlandıktan sonra belirli olayları (events) dinlemeye başlar.
// İstemci tarafı (index.html veya main.js)
const socket = io("http://localhost:3000");
socket.on("bildirim", (data) => {
console.log("Yeni bildirim geldi:", data.mesaj);
alert("Yeni Bildirim: " + data.mesaj);
});
İstemci tarafında socket.on ile sunucudan gelecek olan "bildirim" olayını bekliyoruz. Veri geldiğinde ise kullanıcıya bir arayüz bildirimi gösteriyoruz.
Bildirim Gönderme Mekanizması
Bildirimleri tetiklemek için genellikle bir API endpoint'i kullanılır. Örneğin, bir veritabanı işlemi gerçekleştikten sonra sunucu üzerinden tüm bağlı kullanıcılara veya belirli bir kullanıcıya mesaj gönderebiliriz.
// Sunucu tarafında bildirim gönderme fonksiyonu
app.post('/bildirim-gonder', express.json(), (req, res) => {
const { mesaj, kullaniciId } = req.body;
// Tüm kullanıcılara gönder
io.emit('bildirim', { mesaj });
res.status(200).send({ status: 'Başarılı' });
});
Bu örnekte, bir POST isteği ile sunucuya bildirim tetiklenir. io.emit komutu, sunucuya bağlı olan tüm istemcilere veriyi anında yayınlar.
WebSocket ve HTTP Karşılaştırması
Bildirim sistemlerinde hangi yöntemin seçileceği, projenin ölçeğine ve ihtiyaçlarına bağlıdır. Aşağıdaki tablo, geleneksel HTTP ile WebSocket arasındaki temel farkları özetler.
| Özellik | HTTP (Polling) | WebSocket |
|---|---|---|
| İletişim Yönü | Tek yönlü (İstemci başlatır) | Çift yönlü (Full-duplex) |
| Gecikme (Latency) | Yüksek | Çok Düşük |
| Sunucu Yükü | Yüksek (Sürekli sorgu) | Düşük (Sadece veri aktarımı) |
Güvenlik ve Ölçeklendirme Uyarıları
Kritik Uyarı: WebSocket bağlantılarında kimlik doğrulama (authentication) ihmal edilmemelidir. Bağlantı kurulurken mutlaka JWT (JSON Web Token) gibi yöntemlerle kullanıcının kimliğini doğrulayın. Ayrıca, üretim ortamında
origin: "*"ayarını mutlaka güvenli domain adreslerinizle kısıtlayın.
Üretim ortamında (production) bildirim servisi ölçeklenirken, tek bir sunucu yeterli olmayabilir. Redis kullanarak Socket.io'nun adapter yapısı üzerinden çoklu sunucu (multi-instance) desteği sağlayabilirsiniz.
Sıkça Sorulan Sorular
WebSocket bağlantısı koptuğunda ne olur?
Socket.io kütüphanesi otomatik olarak yeniden bağlanma (reconnection) mekanizmasına sahiptir. İstemci, sunucuya ulaşamadığında belirli aralıklarla tekrar deneme yapar.
Aynı anda binlerce kullanıcıya bildirim göndermek sunucuyu yorar mı?
Evet, ancak doğru bir mimari ile (örneğin Redis Pub/Sub kullanarak) yükü dağıtabilirsiniz. Node.js'in olay döngüsü (event loop) yapısı sayesinde binlerce eşzamanlı bağlantıyı yönetmek oldukça verimlidir.
Bildirimleri veritabanına kaydetmeli miyim?
Evet, WebSocket üzerinden gönderilen bildirimler geçicidir. Kullanıcı çevrimdışıysa bildirimi kaçıracaktır. Bu yüzden bildirimleri veritabanında saklayıp, kullanıcı giriş yaptığında "okunmamış bildirimler" olarak çekmek en iyi pratiktir.
Özel (Private) bildirimleri nasıl gönderirim?
Socket.io'da socket.join(userId) kullanarak kullanıcıları odalara (rooms) ayırabilir ve io.to(userId).emit(...) komutu ile sadece o kullanıcıya özel veri gönderebilirsiniz.
WebSocket yerine Server-Sent Events (SSE) kullanılır mı?
SSE, sadece sunucudan istemciye tek yönlü veri akışı için harikadır ve HTTP üzerinden çalıştığı için daha basittir. Ancak iki yönlü etkileşim gereken durumlarda WebSocket çok daha avantajlıdır.
WebSocket Bildirim Servislerinde Performans Optimizasyonu ve İzleme
WebSocket bağlantıları, HTTP isteklerine göre çok daha az kaynak tüketse de, binlerce eşzamanlı bağlantı yönetildiğinde sunucu tarafında bellek kullanımı ciddi bir sorun haline gelebilir. Performansı optimize etmek için sadece bağlantı sayısına değil, veri paketlerinin boyutuna ve sıklığına da odaklanmalısınız.
Mesaj Kuyruklama ve Redis Kullanımı
Büyük ölçekli uygulamalarda, bildirimleri doğrudan WebSocket üzerinden göndermek yerine bir mesaj kuyruğu (Message Broker) kullanmak, sunucunun yükünü dengeler. Özellikle Redis kullanarak "Pub/Sub" mekanizmasını devreye almak, birden fazla sunucu örneği (instance) arasında bildirim senkronizasyonu sağlar.
// Redis kullanarak bildirim yayını (Örnek mantık)
const redis = require('redis');
const publisher = redis.createClient();
function sendNotificationToUser(userId, message) {
// Mesajı Redis kanalına yayınla
publisher.publish('notifications', JSON.stringify({ userId, message }));
}
// Socket.io sunucusu Redis adaptörü ile bağlanır
const { createClient } = require('redis');
const { createAdapter } = require('@socket.io/redis-adapter');
const pubClient = createClient({ url: 'redis://localhost:6379' });
const subClient = pubClient.duplicate();
io.adapter(createAdapter(pubClient, subClient));
WebSocket Bağlantılarında Hata Ayıklama ve Test Stratejileri
WebSocket uygulamalarında hata ayıklamak, geleneksel REST API'lere göre daha karmaşıktır çünkü bağlantı durumu süreklidir. Bağlantı kopmaları, "handshake" hataları veya paket kayıpları genellikle istemci ve sunucu arasındaki ağ katmanında yaşanır.
İstemci Tarafı Bağlantı Durumu İzleme
Kullanıcı deneyimini iyileştirmek için istemci tarafında bağlantı durumlarını dinlemek ve buna göre UI (arayüz) güncellemesi yapmak kritik öneme sahiptir. Socket.io, bağlantı kopmalarını otomatik yönetse de, geliştirici olarak bu durumu kullanıcıya bildirmek profesyonel bir yaklaşımdır.
// İstemci tarafında bağlantı durumunu izleme
socket.on('connect', () => {
console.log('Sunucuya bağlandı, bildirimler aktif.');
});
socket.on('disconnect', (reason) => {
if (reason === 'io server disconnect') {
// Bağlantı sunucu tarafından kesildi, manuel yeniden bağlan
socket.connect();
}
console.warn('Bağlantı koptu:', reason);
});
socket.on('connect_error', (err) => {
console.error('Bağlantı hatası oluştu:', err.message);
});
Yük Testi İçin Araçlar
Uygulamanızın canlıya çıkmadan önce ne kadar yükü kaldırabileceğini test etmek için Artillery veya Locust gibi araçları kullanabilirsiniz. Özellikle artillery-engine-socketio eklentisi, binlerce sanal kullanıcıyı simüle ederek WebSocket sunucunuzun performans darboğazlarını görmenizi sağlar.
İpucu: WebSocket sunucunuzu test ederken her zaman "ping/pong" mekanizmasının çalıştığından ve sunucunun boşta kalan (idle) bağlantıları belirli bir süre sonra temizlediğinden (timeout) emin olun.
Sonuç
Node.js ve Socket.io kullanarak bildirim servisi oluşturmak, modern web uygulamaları için en performanslı çözümlerden biridir. Bu rehberde, kurulumdan başlayarak sunucu ve istemci arasındaki iletişimi, güvenliği ve ölçeklendirme mantığını ele aldık. Bir sonraki adım olarak, bildirimleri veritabanı ile entegre etmeyi ve kullanıcıların çevrimdışı olduklarında kaçırdıkları bildirimleri yönetmeyi deneyebilirsiniz.
Yasal Uyarı: Bu rehberdeki kodlar eğitim amaçlıdır. Yazılım geliştirme süreçlerinde güvenlik yamalarını takip etmek, bağımlılıkları güncel tutmak ve sunucu güvenliğini (firewall, rate limiting) sağlamak geliştiricinin sorumluluğundadır. Bu makale herhangi bir hukuki veya ticari tavsiye niteliği taşımaz.


Yorumlar (0)
Yorum Yaz