WebSocket sunucusu, gerçek zamanlı veri almak üzere tasarlanmıştır; bu, tarayıcınızda bir bağlantı açıp veri (örneğin html, xml, json vb.) aldığınız klasik bir web sunucusunun aksine çalışır. Klasik bir sunucu, bir bağlantı kurar -> veri iletir -> bağlantıyı sonlandırır.
Bir WebSocket sunucusu farklı çalışır: onunla bir bağlantı kurarsınız ve bu bağlantı sürekli aktif kalır. Veriler değişir değişmez, sunucu bunları istemciye iletir. Çift yönlü iletişim kullandığı için bağlantı her zaman aktiftir ve sonlandırılmaz.
1. Uygulama
Gerçek zamanlı veri almak için kullanılır. Örneğin, web sitenizin ziyaretçilerini veya çevrimiçi mağazanızın sipariş durumunu ayrı bir web sayfasında veya hatta ayrı bir cihazda canlı olarak göstermek isterseniz.
2. Nasıl Çalışır
Bir WebSocket sunucusu, sonraki bağlantılar için atadığınız özel bir portta çalışan ayrı bir hizmettir. WS (WebSocket sunucusu) veya WSS (WebSocket sunucusu + SSL) protokolü, örneğin html + JS kullanarak bir tarayıcı aracılığıyla gerçek zamanlı güncellemelerle veri çıkışını yapılandırmanıza olanak tanır.
Lütfen dikkat! Hizmet yeni bir port açmayı gerektirdiğinden, böyle bir hizmetin kurulumu ve çalıştırılması yalnızca sanal bir sunucuda mümkündür. İşte tam da bu nedenle WebSocket sunucusu, paylaşımlı barındırma hizmetleri için mevcut değildir.
Her paylaşımlı barındırma müşterisinin böyle bir hizmeti çalıştırmak istediğini hayal edin: her biri için ayrı bir port açılması gerekir ki bu da hizmetin güvenliğini tehlikeye atacaktır. Barındırma sağlayıcısından bağımsız olarak, kurulum ve çalıştırma yalnızca bir VPS/VDS sunucusunda mümkündür.
3. Görev Örneği
https://domain.tld/online-orders.php adresinde JSON formatında veri çıktısı üreten bir PHP betiğimiz olduğunu ve bu verilerin gerçek zamanlı olarak gösterilmesini istediğimizi varsayalım. Şu anda, bunu başarmak sürekli yenileme gerektiriyor.
Şunu belirtmek gerekir ki, bir PC ve tarayıcı için veriler istek sıklığı artırılarak güncellenebilirken, bir mikrodenetleyiciden sık sık istek ve JSON veri güncellemeleri yapılması durumunda, bu sadece 1-2 saniye boyunca takılmasına neden olacaktır. Ve örneğin, her 20 saniyede bir yapılan düzenli bir POST/GET isteği hala gerçek zamanlı değildir.
Bu nedenle WSS'ye ihtiyacımız var. Debian 12 üzerinde minimum kaynak yapılandırmasına sahip yeni bir VPS başlatacağız. WSS için yüksek performans gerekmez. Tüm yapılandırmalar root kullanıcısı olarak gerçekleştirilecektir.
3.1 Hizmet Kurulumu
apt update
apt install -y curl git nodejs npm
3.2 WebSocket Projesi Oluşturma
mkdir ~/websocket-server
cd ~/websocket-server
npm init -y
npm install ws node-fetch express
3.3 websocket-server projesinin kökünde bir yapılandırma dosyası oluşturalım
nano server.js
import express from "express";
import { WebSocketServer } from "ws";
import fetch from "node-fetch";
import https from "https";
import fs from "fs";
// === Ayarlar ===
const PORT = 8080; // Bu WebSocket sunucusu için bir port seçin
const FETCH_URL = "https://domain.tld/online-orders.php";
const FETCH_INTERVAL = 1000; // Her 1 saniyede bir
// === HTTPS Sertifikaları ===
// (WSS gerekiyorsa, bir SSL sertifikası gereklidir. Let's Encrypt veya kendinden imzalı kullanabilirsiniz)
const options = {
key: fs.readFileSync("/etc/ssl/private/your-key.pem"),
cert: fs.readFileSync("/etc/ssl/certs/your-cert.pem")
};
// === HTTP(S) Sunucusu + WebSocket ===
const app = express();
const server = https.createServer(options, app);
const wss = new WebSocketServer({ server });
let latestData = null;
// === Periyodik JSON İsteği ===
async function updateData() {
try {
const res = await fetch(FETCH_URL);
const json = await res.json();
latestData = json;
// Tüm bağlı istemcilere gönder
wss.clients.forEach(client => {
if (client.readyState === 1) { // WebSocket.OPEN
client.send(JSON.stringify(json));
}
});
} catch (err) {
console.error("Veri alınırken hata oluştu:", err);
}
}
setInterval(updateData, FETCH_INTERVAL);
updateData(); // İlk yükleme
// === WebSocket Bağlantısı ===
wss.on("connection", ws => {
console.log("İstemci bağlandı");
if (latestData) ws.send(JSON.stringify(latestData));
ws.on("close", () => console.log("İstemci bağlantısı kesildi"));
});
server.listen(PORT, () => {
console.log(`WSS sunucusu ${PORT} portunda başlatıldı`);
});
3.4 Let's Encrypt aracılığıyla WSS için SSL Kurulumu
SSL için bir alan adı gereklidir. Örneğin, ws.domain.tld gibi bir alt alan adı kullanacağız.
apt install certbot python3-certbot-nginx
certbot certonly --standalone -d ws.domain.tld
Bildirimler için bir e-posta adresi sağlayarak kısa prosedürü takip edin. Tamamlandığında, sertifika ve anahtar burada olacaktır:
/etc/letsencrypt/live/ws.domain.tld/fullchain.pem
/etc/letsencrypt/live/ws.domain.tld/privkey.pem
server.js dosyasındaki yolları değiştirin:
const options = {
key: fs.readFileSync("/etc/letsencrypt/live/ws.domain.tld/privkey.pem"),
cert: fs.readFileSync("/etc/letsencrypt/live/ws.domain.tld/fullchain.pem")
};
3.5 Çalıştırma ve Hata Ayıklama
node server.js
SyntaxError: Cannot use import statement outside a module hatası aldık.
Bu durumda, package.json dosyasını "type": "module", satırını ekleyerek değiştirmeniz gerekir.
package.json dosyasının doğru yapılandırma örneği:
{
"name": "websocket-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
...
Tekrar çalıştırın:
node server.js
WSS sunucusu 8080 portunda başlatıldı
İstemci bağlandı
3.6 Otomatik Başlatmayı Yapılandırma:
npm install -g pm2
pm2 start server.js --name websocket
pm2 save
pm2 startup
3.7 Hizmetin Çalışmasını Kontrol Etme
pm2 list
3.8 HTML ve JS Kullanarak Bağlanma
PC'nizde wss-client.html adında bir dosya oluşturun ve içine aşağıdaki içeriği yapıştırın:
Bir web sunucusu gibi doğrudan bir tarayıcıda bir alan adı üzerinden WebSocket'e bağlanamazsınız; bir betik oluşturmanız gerekir. ws.domain.tld yerine kendi alan adınızı belirtin.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>WSS Testi</title>
<style>
body {
font-family: monospace;
background: #111;
color: #0f0;
padding: 20px;
}
input, button {
background: #222;
color: #0f0;
border: 1px solid #0f0;
padding: 6px 10px;
font-family: monospace;
}
#log {
margin-top: 20px;
white-space: pre-wrap;
background: #000;
border: 1px solid #0f0;
padding: 10px;
height: 400px;
overflow-y: auto;
}
</style>
</head>
<body>
<h2>🔌 WebSocket Test İstemcisi</h2>
<label>Sunucu URL:</label>
<input id="wsUrl" type="text" size="50" value="wss://ws.domain.tld:8080">
<button onclick="connect()">Bağlan</button>
<button onclick="disconnect()">Bağlantıyı Kes</button>
<div id="status">Durum: <b>Bağlantı Kesildi</b></div>
<div id="log"></div>
<script>
let ws;
function log(msg) {
const logDiv = document.getElementById('log');
logDiv.innerText += msg + "\n";
logDiv.scrollTop = logDiv.scrollHeight;
}
function connect() {
const url = document.getElementById('wsUrl').value;
ws = new WebSocket(url);
log("🔄 " + url + " adresine bağlanılıyor ...");
document.getElementById('status').innerHTML = "Durum: <b>Bağlanıyor...</b>";
ws.onopen = () => {
log("✅ Bağlantı kuruldu");
document.getElementById('status').innerHTML = "Durum: <b style='color:lime'>Bağlandı</b>";
};
ws.onmessage = event => {
try {
const json = JSON.parse(event.data);
log("📦 Alındı:\n" + JSON.stringify(json, null, 2));
} catch (e) {
log("📦 Metin:\n" + event.data);
}
};
ws.onclose = () => {
log("❌ Bağlantı kapatıldı");
document.getElementById('status').innerHTML = "Durum: <b style='color:red'>Bağlantı Kesildi</b>";
};
ws.onerror = err => {
log("⚠️ Hata: " + err.message);
};
}
function disconnect() {
if (ws) {
ws.close();
ws = null;
}
}
</script>
</body>
</html>
3.9 Günlükleri Görüntüleme
Bağlantı çalışmalıdır; betiğimizdeki veriler değişir değişmez, WebSocket bağlı tüm istemciler için bunları güncelleyecektir.
Olay günlüğünü şu komutla görüntüleyebilirsiniz:
pm2 logs websocket
0|websocket | 5 ziyaret güncellendi
4. Yetkilendirme
Yukarıdaki örnekte, herkes WebSocket sunucusuna bağlanabilir, bu yüzden token tabanlı yetkilendirme ekleyelim.
Güncellenmiş server.js kodu:
import express from "express";
import { WebSocketServer } from "ws";
import fetch from "node-fetch";
import https from "https";
import fs from "fs";
import url from "url";
// === Ayarlar ===
const PORT = 8080;
const FETCH_URL = "https://domain.tld/online-orders.php";
const FETCH_INTERVAL = 1000; // Her 1 saniyede bir
const VALID_TOKENS = ["ABC123", "ESP32TOKEN", "MYSECRET"]; // İzin verilen token listesi
// === SSL ===
const options = {
key: fs.readFileSync("/etc/letsencrypt/live/ws.domain.tld/privkey.pem"),
cert: fs.readFileSync("/etc/letsencrypt/live/ws.domain.tld/fullchain.pem")
};
// === Sunucu Oluşturma ===
const app = express();
const server = https.createServer(options, app);
const wss = new WebSocketServer({ server });
let latestData = null;
// === Periyodik JSON Alma Fonksiyonu ===
async function updateData() {
try {
const res = await fetch(FETCH_URL);
const json = await res.json();
latestData = json;
// Tüm aktif istemcilere gönder
wss.clients.forEach(client => {
if (client.readyState === 1) { // WebSocket.OPEN
client.send(JSON.stringify(json));
}
});
} catch (err) {
console.error("Veri alınırken hata oluştu:", err);
}
}
setInterval(updateData, FETCH_INTERVAL);
updateData();
// === Bağlantıları Yönetme ===
wss.on("connection", (ws, req) => {
const query = url.parse(req.url, true).query;
const token = query.token;
if (!VALID_TOKENS.includes(token)) {
console.log(`❌ Token: ${token} ile bağlantı reddedildi`);
ws.close(4001, "Invalid token");
return;
}
console.log(`✅ Token: ${token} ile istemci bağlandı`);
// En son durumu gönder
if (latestData) ws.send(JSON.stringify(latestData));
ws.on("close", () => {
console.log(`🔌 İstemci (${token}) bağlantısı kesildi`);
});
});
server.listen(PORT, () => {
console.log(`✅ WSS sunucusu ${PORT} portunda başlatıldı`);
});
4.1 Token Yetkilendirmesi ile Bağlantı
HTML + JS kullanan bir örnek için, satırı basitçe şöyle değiştirin:
<input id="wsUrl" value="wss://ws.domain.tld:8080/?token=ABC123">
5. Sonuç
Kurulum tamamlandı; artık tüm WebSocket sunucusu istemcileri şifreleme kullanarak gerçek zamanlı veri alıyor. Örneğimizde, sistemi (bir API kullanarak veri almak için) ve WebSocket sunucusunu (veriyi iletmek için) arasında bir aracı olarak bir PHP betiği kullandık.
PHP betiğinin kendisi kaldırılabilir ve API yetkilendirmesiyle doğrudan server.js içinde bir API isteği kullanılabilir, bu daha da verimli olacaktır. Ancak, bu durumda makale oldukça kapsamlı hale gelecektir, çünkü API anahtarının .env dosyasında güvenli bir şekilde saklanması ve yapılandırma dosyası verileriyle çalışmak için npm install dotenv paketinin kurulumu gibi konuları ele almak gerekecektir.

