Ön Hazırlık ve Gereksinimler
Projenize başlamadan önce bilgisayarınızda Node.js'in güncel bir sürümünün (LTS 22.x veya üzeri) kurulu olması gerekmektedir. React projenizi oluşturmak için Vite kullanacağız, çünkü Vite, modern tarayıcılar ve hızlı geliştirme süreçleri için en optimize araçtır.
- Node.js (v22+)
- npm veya pnpm paket yöneticisi
- Temel React ve Hooks (useState, useEffect) bilgisi
- Socket.io-client kütüphanesi
Öncelikle terminalinizde yeni bir React projesi oluşturun ve gerekli bağımlılıkları yükleyin:
npm create vite@latest notification-app -- --template react
cd notification-app
npm install socket.io-client
Bu komutlar, projenizin temel iskeletini kuracak ve gerçek zamanlı haberleşme için gerekli olan Socket.io istemci kütüphanesini projenize dahil edecektir.
Websocket Mimarisi ve İletişim Mantığı
Websocket, istemci ve sunucu arasında kalıcı bir TCP bağlantısı açarak verilerin her iki yönde de anlık akmasını sağlar. HTTP protokolü "istek atıldığında yanıt al" mantığıyla çalışırken, Websocket "bağlantı açık olduğu sürece veri gönder" mantığıyla çalışır. Bildirim sistemlerinde bu, sunucunun veritabanında bir değişiklik olduğunda (örneğin yeni bir mesaj geldiğinde) istemciye "push" (itme) yapabilmesi anlamına gelir.
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Polling (HTTP) | Basit kurulum | Yüksek sunucu yükü, gecikme |
| Websocket | Düşük gecikme, çift yönlü | Bağlantı yönetimi gerektirir |
| SSE (Server-Sent Events) | Tek yönlü akış için hafif | Çift yönlü değil |
React İçinde Socket Bağlantısını Kurma
React uygulamamızda socket bağlantısını yönetmek için bir "context" yapısı veya özel bir kanca (custom hook) kullanmak en temiz yöntemdir. Bu sayede bağlantı yönetimini bileşenlerinizden soyutlamış olursunuz. Aşağıdaki örnekte, bağlantıyı merkezi bir noktada nasıl yöneteceğimizi göreceksiniz.
import { io } from "socket.io-client";
// Sunucu adresini ve yapılandırmayı tanımlıyoruz
const socket = io("https://api.uygulamaniz.com", {
autoConnect: false, // Manuel kontrol için
transports: ["websocket"]
});
export default socket;
Bu dosya, uygulamanızın herhangi bir yerinde socket örneğine erişmenizi sağlar. autoConnect: false ayarı, bağlantıyı uygulamanın yüklenme anında değil, ihtiyaç duyulduğunda (örneğin kullanıcı giriş yaptığında) açmanıza olanak tanır.
Bildirimleri Dinleme ve State Güncelleme
Bildirimleri almak için useEffect kancasını kullanacağız. Bileşen bağlandığında (mount) socket olaylarını dinlemeye başlayacağız ve bileşen yok olduğunda (unmount) bu dinleyicileri temizleyeceğiz. Bu, bellek sızıntılarını önlemek için kritik bir adımdır.
import { useEffect, useState } from "react";
import socket from "./socket";
function NotificationComponent() {
const [notifications, setNotifications] = useState([]);
useEffect(() => {
socket.connect();
// 'new-notification' olayını dinle
socket.on("new-notification", (data) => {
setNotifications((prev) => [data, ...prev]);
});
// Temizlik işlemi
return () => {
socket.off("new-notification");
socket.disconnect();
};
}, []);
return (
{notifications.map((n, index) => {n.message}
)}
);
}
Burada setNotifications fonksiyonuna bir fonksiyon geçerek, önceki bildirimlerin üzerine yenisini ekliyoruz. Bu, React'in state güncellemelerindeki asenkron doğası gereği en güvenli yöntemdir.
Güvenlik ve Performans İpuçları
Websocket bağlantılarında güvenlik, HTTP istekleri kadar önemlidir. XSS (Cross-Site Scripting) saldırılarına karşı gelen veriyi render etmeden önce mutlaka temizlemelisiniz. Ayrıca bağlantılarınızı yetkilendirilmiş (authenticated) kullanıcılara özel tutmalısınız.
Kritik Uyarı: Üretim ortamında (production) socket bağlantılarınızı mutlaka JWT (JSON Web Token) ile yetkilendirin. Sunucu tarafında
io.use((socket, next) => {...})ara katmanını kullanarak bağlantı kuran kullanıcının kimliğini doğruladığınızdan emin olun. Aksi takdirde sunucunuz yetkisiz veri akışına maruz kalabilir.
Performans için ise, çok fazla bildirim gelmesi durumunda state'i sınırlamayı unutmayın. Örneğin, sadece son 10 bildirimi tutmak uygulamanızın daha hızlı çalışmasını sağlar.
// Sadece son 10 bildirimi tutan mantık
setNotifications((prev) => [data, ...prev].slice(0, 10));
Bağlantı Hatalarını Yönetme
Gerçek dünya uygulamalarında internet kesintileri kaçınılmazdır. Socket.io, otomatik yeniden bağlanma (reconnect) özelliklerine sahiptir ancak arayüzde kullanıcıya durum hakkında bilgi vermek profesyonel bir yaklaşımdır.
useEffect(() => {
socket.on("connect_error", (err) => {
console.error("Bağlantı hatası:", err.message);
});
socket.on("reconnect", (attemptNumber) => {
console.log("Yeniden bağlandı, deneme:", attemptNumber);
});
}, []);
Bu kod bloğu, bağlantı koptuğunda veya hata oluştuğunda geliştirici konsolunda takip edilebilir loglar oluşturur. Kullanıcıya "Bağlantı kuruluyor..." gibi bir uyarı göstermek için bu olayları bir state'e bağlayabilirsiniz.
Sıkça Sorulan Sorular
Websocket bağlantısı mobil cihazlarda pil tüketimini artırır mı?
Evet, sürekli açık bir bağlantı pil tüketimine neden olabilir. Ancak modern tarayıcılar ve Socket.io, bağlantı boşta kaldığında bunu optimize eder. Yine de çok yoğun veri akışı olmayan durumlarda bağlantıyı yönetmek önemlidir.
Neden Socket.io yerine saf Websocket API kullanmıyorum?
Saf Websocket API, bağlantı düşmelerinde otomatik yeniden bağlanma, oda (room) yönetimi veya broadcast gibi özellikleri desteklemez. Socket.io, bu karmaşık süreçleri sizin yerinize yöneten sağlam bir katman sunar.
Bildirimleri veritabanına kaydetmeli miyim?
Evet, anlık bildirimler "geçicidir". Kullanıcı sayfayı yenilediğinde bildirimlerin kaybolmaması için, gelen bildirimi önce veritabanına yazıp ardından socket üzerinden broadcast etmelisiniz.
Aynı anda binlerce kullanıcıya bildirim göndermek sunucuyu yorar mı?
Doğrudan tek bir sunucudan binlerce kişiye yayın yapmak darboğaz yaratır. Bu durumda Redis kullanarak "Pub/Sub" yapısını kurmanız ve socket sunucularını yatay ölçeklendirmeniz (scaling) gerekir.
Bildirimleri tarayıcı kapalıyken alabilir miyim?
Hayır, standart bir React uygulaması tarayıcı kapalıyken çalışmaz. Bu durum için "Service Worker" ve "Push API" kullanmanız gerekir.
WebSocket Uygulamalarında Performans Optimizasyonu ve Ölçeklendirme
Gerçek zamanlı uygulamaların kullanıcı sayısı arttıkça, sunucu üzerindeki yük doğrusal değil, bazen katlanarak artabilir. WebSocket bağlantılarını yönetirken performans kaybını önlemek için uygulamanız gereken bazı stratejik yaklaşımlar mevcuttur.
Mesajlaşma Yükünü Hafifletme
Her bir WebSocket mesajı bir paket yükü oluşturur. Özellikle çok sık güncellenen verilerde (örneğin borsa verileri veya anlık konum takibi), mesajları gruplandırarak (batching) göndermek ağ trafiğini rahatlatır. Ayrıca, JSON verilerini küçültmek için gereksiz alanları temizlemek veya MessagePack gibi ikili (binary) formatlar kullanmak, bant genişliği kullanımını ciddi oranda düşürür.
Redis Pub/Sub ile Yatay Ölçeklendirme
Tek bir sunucu artık yetmediğinde, WebSocket bağlantılarını birden fazla sunucuya dağıtmanız gerekir. Ancak, A sunucusuna bağlı bir kullanıcıya, B sunucusundaki bir olaydan bildirim göndermek için bir "mesaj aracısı" (message broker) kullanmalısınız. Redis Pub/Sub bu noktada standarttır.
// Basitleştirilmiş Redis Pub/Sub mantığı
const redis = require('redis');
const subscriber = redis.createClient();
subscriber.subscribe('notification_channel');
subscriber.on('message', (channel, message) => {
// Tüm bağlı istemcilere mesajı ilet
io.emit('new_notification', JSON.parse(message));
});
WebSocket Bağlantılarında Hata Ayıklama ve İzleme
WebSocket bağlantıları "durumlu" (stateful) oldukları için hata ayıklaması HTTP isteklerine göre daha karmaşıktır. Bağlantının neden koptuğunu veya mesajların neden ulaşmadığını anlamak için doğru araçları kullanmak kritik öneme sahiptir.
Tarayıcı Geliştirici Araçlarını Etkin Kullanma
Chrome veya Firefox'un "Network" sekmesinde yer alan "WS" filtresi, WebSocket trafiğini anlık olarak izlemenizi sağlar. Burada "Frames" sekmesine tıklayarak, sunucu ile istemci arasında gidip gelen ham veriyi (payload) görebilir, bağlantı sırasında oluşan hata kodlarını (örneğin 1006: anormal kapanma) inceleyebilirsiniz.
Bağlantı Sağlığı İçin "Heartbeat" Mekanizması
Bazen bağlantı kopmasına rağmen istemci veya sunucu bunu hemen fark etmeyebilir ("zombi bağlantılar"). Bunu engellemek için düzenli aralıklarla "ping-pong" mekanizması kurmalısınız.
// İstemci tarafında basit bir ping-pong kontrolü
const socket = new WebSocket('ws://example.com');
const heartbeat = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'ping' }));
}
}, 30000); // Her 30 saniyede bir kontrol et
socket.onclose = () => clearInterval(heartbeat);
İzleme (Monitoring) Stratejileri
Üretim ortamında (production) kaç kullanıcının aktif olduğunu ve bağlantı hatalarının sıklığını takip etmek için Prometheus ve Grafana ikilisini kullanabilirsiniz. WebSocket sunucunuzun metriklerini (aktif bağlantı sayısı, mesaj gecikme süresi) dışa aktararak, sistemin darboğaz yaşadığı anları önceden tespit edebilirsiniz.
İpucu: Eğer uygulamanız çok yüksek trafik alıyorsa, WebSocket trafiğini doğrudan Node.js sunucunuza değil, Nginx gibi bir ters vekil sunucusu (reverse proxy) üzerinden geçirin. Nginx, WebSocket bağlantılarını yönetme ve yük dengeleme (load balancing) konusunda çok daha verimlidir.
Sonuç
React ile Websocket kullanarak anlık bildirim sistemi kurmak, uygulamanızın etkileşimini bir üst seviyeye taşır. Bu rehberde; bağlantı kurulumu, olay dinleme, state yönetimi ve hata ayıklama süreçlerini ele aldık. Unutmayın ki, her başarılı gerçek zamanlı uygulama, sunucu tarafındaki sağlam bir altyapı ile desteklenmelidir.
Yasal Uyarı: Bu rehberdeki kod örnekleri eğitim amaçlıdır. Yazılım geliştirme sürecinde oluşabilecek veri kaybı, güvenlik açıkları veya sunucu hatalarından geliştirici sorumludur. Üretim ortamına geçmeden önce tüm kodları güvenlik testlerinden geçirin ve güncel kütüphane sürümlerini kullanın.
Bir sonraki adım olarak, sunucu tarafında Node.js ve Express kullanarak kendi socket sunucunuzu yazmayı veya Redis entegrasyonu ile uygulamanızı ölçeklendirmeyi deneyebilirsiniz.

Yorumlar (0)
Yorum Yaz