Node.js İle Socket.io Kullanarak Paylaşımlı Canlı Çizim Tahtası Nasıl Yapılır?

Node.js İle Socket.io Kullanarak Paylaşımlı Canlı Çizim Tahtası Nasıl Yapılır?
Node.js İle Socket.io Kullanarak Paylaşımlı Canlı Çizim Tahtası Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Projeye başlamadan önce bilgisayarınızda güncel bir Node.js sürümünün (2026 yılı standartları gereği LTS sürümü önerilir) yüklü olduğundan emin olun. Ayrıca terminal kullanımına aşina olmanız ve temel düzeyde JavaScript bilgisine sahip olmanız yeterlidir.

  • Node.js: Sunucu tarafı çalışma ortamı.
  • Express: HTTP isteklerini yönetmek için kullanılan web framework'ü.
  • Socket.io: İstemci ve sunucu arasında çift yönlü iletişim sağlayan kütüphane.
  • Kod Editörü: VS Code gibi modern bir editör.

Öncelikle projeniz için bir klasör oluşturun ve terminalde şu komutları çalıştırarak gerekli paketleri kurun:

mkdir cizim-tahtasi
cd cizim-tahtasi
npm init -y
npm install express socket.io

Bu komutlar, projenizin temelini oluşturacak olan package.json dosyasını ve gerekli bağımlılıkları içeren node_modules klasörünü oluşturacaktır.

Sunucu Tarafı Yapılandırması

Sunucu tarafında, Express üzerinden bir HTTP sunucusu oluşturacağız ve bu sunucuyu Socket.io ile entegre edeceğiz. Sunucu, istemcilerden gelen çizim verilerini alacak ve bu verileri "yayınlayacak" (broadcast) şekilde yapılandırılacaktır.

// server.js
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);

app.use(express.static('public'));

io.on('connection', (socket) => {
    console.log('Bir kullanıcı bağlandı: ' + socket.id);

    socket.on('cizim', (data) => {
        socket.broadcast.emit('cizim', data);
    });
});

http.listen(3000, () => {
    console.log('Sunucu http://localhost:3000 adresinde çalışıyor.');
});

Burada io.on('connection') bloğu, yeni bir bağlantı kurulduğunda tetiklenir. socket.broadcast.emit metodu ise, çizimi yapan kişi hariç tüm bağlı kullanıcılara veriyi iletmemizi sağlar.

İstemci Tarafı: HTML5 Canvas Kurulumu

İstemci tarafında, kullanıcıların çizim yapabileceği bir elementi oluşturacağız. Bu element, farenin hareketlerini takip ederek koordinat verilerini sunucuya gönderecek.

Bu dosya, Socket.io istemci kütüphanesini otomatik olarak sunucudan çeker ve kendi main.js dosyamızı projeye dahil eder.

JavaScript ile Çizim Mantığını Kodlama

Şimdi farenin hareketlerini yakalayıp sunucuya gönderme ve gelen verileri çizme zamanı. main.js içerisinde Canvas API'sini kullanarak farenin konumu değiştikçe bir çizgi çizeceğiz.

// public/main.js
const socket = io();
const canvas = document.getElementById('tahta');
const ctx = canvas.getContext('2d');
let ciziyor = false;

canvas.addEventListener('mousedown', () => ciziyor = true);
canvas.addEventListener('mouseup', () => ciziyor = false);
canvas.addEventListener('mousemove', (e) => {
    if (!ciziyor) return;
    const veri = { x: e.clientX, y: e.clientY };
    ctx.lineTo(veri.x, veri.y);
    ctx.stroke();
    socket.emit('cizim', veri);
});

socket.on('cizim', (data) => {
    ctx.lineTo(data.x, data.y);
    ctx.stroke();
});

Bu kod bloğu, fare basılı tutulduğunda koordinatları yakalar ve socket.emit ile sunucuya gönderir. Aynı zamanda, sunucudan gelen diğer kullanıcıların verilerini de ctx.lineTo ile ekrana çizer.

Yöntemlerin Karşılaştırılması

Gerçek zamanlı veri iletiminde farklı yaklaşımlar mevcuttur. Aşağıdaki tablo, Socket.io kullanımının diğer yöntemlerle kıyaslamasını göstermektedir:

Yöntem Avantajı Dezavantajı
Socket.io Kolay kurulum, otomatik geri dönüş (fallback) Sunucu yükü daha fazla
Native WebSocket Düşük gecikme, yüksek performans Eski tarayıcı desteği kısıtlı
HTTP Polling Basit yapı Çok yüksek gecikme, verimsiz
Kritik Güvenlik Uyarısı: Üretim ortamında (production) Socket.io kullanırken, mutlaka CORS (Cross-Origin Resource Sharing) ayarlarını yapılandırın. İstemciden gelen verileri sunucuda doğrulamadan doğrudan yayınlamak, XSS veya zararlı veri enjeksiyonlarına yol açabilir. Kullanıcı girdilerini her zaman temizleyin.

Sıkça Sorulan Sorular

Socket.io neden düz WebSocket yerine tercih edilir?

Socket.io, WebSocket protokolünü temel alsa da, bağlantı kopmalarında otomatik yeniden bağlanma ve eski tarayıcılar için HTTP polling gibi yedekleme mekanizmalarına sahiptir.

Çizimler sayfa yenilenince neden kayboluyor?

Çünkü veriler şu an sadece RAM üzerinde tutuluyor. Kalıcı olmasını istiyorsanız, çizim verilerini Redis veya MongoDB gibi bir veritabanında saklamalı ve yeni bağlanan kullanıcıya veritabanındaki geçmişi göndermelisiniz.

Birden fazla renk veya fırça boyutu nasıl eklenir?

socket.emit ile gönderdiğiniz nesneye color ve size gibi özellikleri ekleyerek, sunucudan gelen veriyi işlerken ctx.strokeStyle ve ctx.lineWidth değerlerini güncelleyebilirsiniz.

Bu uygulama kaç kişiyi aynı anda destekler?

Node.js tek iş parçacıklı (single-threaded) olduğu için, çok sayıda kullanıcıda sunucu yükü artacaktır. Ölçeklendirme için "Redis Adapter" kullanarak birden fazla sunucu örneği (cluster) kurmanız önerilir.

Mobil cihazlarda çizim yaparken neden kayma oluyor?

Mobil cihazlarda mousemove yerine touchmove olaylarını dinlemeniz ve koordinatları e.touches[0].clientX üzerinden almanız gerekmektedir.

Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Yazılımlarınızın güvenliği ve veri bütünlüğü tamamen geliştiricinin sorumluluğundadır. Üretim ortamına geçmeden önce güvenlik testlerini tamamlamanız önerilir.

Performans Optimizasyonu ve Veri Akışını Yönetme

Gerçek zamanlı çizim uygulamalarında, her fare hareketinde sunucuya veri göndermek yüksek trafikli anlarda ağ darboğazlarına yol açabilir. Kullanıcı deneyimini bozmadan performansı artırmak için "throttling" (kısıtlama) ve "batching" (gruplama) tekniklerini uygulamak kritik öneme sahiptir.

Aşağıdaki örnekte, requestAnimationFrame kullanarak çizim verilerinin gönderimini tarayıcının ekran yenileme hızına nasıl senkronize edebileceğinizi görebilirsiniz:

let drawingData = [];
const socket = io();

function drawAndEmit(data) {
    // Yerel çizim işlemleri burada yapılır
    drawingData.push(data);
}

// Veriyi belirli aralıklarla toplu gönder
setInterval(() => {
    if (drawingData.length > 0) {
        socket.emit('drawing_batch', drawingData);
        drawingData = []; // Gönderim sonrası temizle
    }
}, 50); // 50ms'de bir gönderim yaparak ağ trafiğini minimize edin

Bu yöntem, sunucunun saniyede binlerce küçük paket yerine, daha az sayıda ancak daha kapsamlı paket işlemesini sağlar. Ayrıca, sunucu tarafında socket.broadcast.emit yerine socket.to(room).emit kullanarak veriyi sadece ilgili odadaki kullanıcılara iletmek, gereksiz veri trafiğini engelleyecektir.

Uygulamayı Yayına Alma (Deployment) İpuçları

Projenizi yerel ortamdan canlı sunucuya taşırken dikkat etmeniz gereken en önemli husus, Socket.io'nun oturum (session) yönetimidir. Eğer uygulamanızı birden fazla sunucu örneği (multi-instance) üzerinde çalıştıracaksanız, Socket.io'nun bağlantıları eşitlemesi için bir Redis Adapter kullanmanız zorunludur.

Nginx ile Ters Vekil Sunucu (Reverse Proxy) Yapılandırması

Uygulamanızı canlıya alırken Nginx kullanarak WebSocket bağlantılarını doğru şekilde yönlendirmelisiniz. Aksi takdirde, bağlantı sürekli kopabilir veya "handshake" hataları alabilirsiniz.

location /socket.io/ {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

Ayrıca, üretim ortamında mutlaka bir Process Manager (örneğin PM2) kullanarak uygulamanızın çökmesi durumunda otomatik olarak yeniden başlamasını sağlamalısınız. PM2, aynı zamanda uygulama loglarını takip etmenize ve CPU/RAM kullanımını izlemenize olanak tanır.

İpucu: Canlı ortamda güvenlik için CORS ayarlarını mutlaka kısıtlayın. Sadece kendi alan adınızdan gelen isteklere izin vererek, uygulamanızın kötü niyetli sunucular tarafından "socket spam" saldırısına uğramasını engelleyebilirsiniz.

Sonuç

Node.js ve Socket.io kullanarak canlı bir çizim tahtası yapmak, gerçek zamanlı web uygulamalarının temellerini anlamak için harika bir projedir. Bu aşamada, temel bir bağlantı kurmayı ve veri iletimini gerçekleştirmeyi başardınız. Bir sonraki adım olarak, çizim tahtasına renk seçimi, fırça boyutu ayarı veya "tahtayı temizle" gibi fonksiyonlar ekleyerek projenizi geliştirebilirsiniz. Gerçek zamanlı sistemlerde ustalaşmak için bir sonraki aşamada Redis kullanarak durum yönetimi (state management) konusuna odaklanmanızı öneririm.

Bu yazıya tepkinizi paylaşın:
Emre Çelik

Verimlilik ve zaman yönetimi üzerine odaklanan bir yazarım. Günlük hayatı optimize eden ipuçları ve iş akışı optimizasyonu konularında içerikler üretiyorum.

Yorumlar (0)

Yorum Yaz