5N 1K — WebSocket(C#, Javascript)

Muhammed Emin KARABOĞA
Intertech
Published in
7 min readJan 24, 2024

Merhaba ,

Uzun bir zaman geçtikten sonra ne ile uğraşmalıyım diye çok düşüneniz olmuştur elbet. Ben de böyle bir zamandan geçerken yakın bir dostumun whatsapp mesajı bana ilham oldu. :)
Mesajın içeriği değil elbet. :) WhatsApp ın kendisi :D

Nedir bu WhatsApp ve nasıl çalışıyor diye düşünmeye başladığım an meşkalemi bulmuş oldum. :) Bir WhatsApp kullanıcısı nasıl oluyor da yazıştığı kişinin “yazıyor / typing” durumunu anlık olarak görüyor. Arada kopmayan ve kalıcı bağlantının olduğu apacık belliydi. Peki bu nasıl oluyordu.

Bu konuda küçük bir kaç araştırma yapınca kendimi WebSocket kavramında buldum :) Bu yazının devamında WhatasApp ın detaylı bir teknik analizi yapıyor olmayacağım :) Sadece bir chat uygulamasının real-time amaçlı WebSocket i nasıl kullanabileceği yönünde küçük bir anlama ve örneklendirme çabası içerisinde olacağımı belirtmek istiyorum. :)

O halde başlayalım.

5N1K ile WebSocket!

WebSocket nedir?

Ne Zaman WebSocket i kullanmalıyız?

Niçin WebSocket?

Kimler WebSocket i kullanmalı?

WebSocket Nasıl Kullanılır ? (Uygulama)

1 ) WebSocket Nedir?

Bu bölümde WebSocket in ne olduğunu anlamak için HTTP ile kısa bir karşılaştırmasını yapalım. :)

WebSocket, iki yönlü iletişimi destekleyen bir ağ iletişim protokolüdür. Bu protokol, web tarayıcıları ile sunucular arasında gerçek zamanlı(real-time), etkileşimi ile sürekli veri transferine olanak tanır.

HTTP, istemci-sunucu modeline dayanan bir protokoldür. İstemci, sunucuya bir istek gönderir ve sunucu da isteğe yanıt olarak bir cevap gönderir. Her iki taraf her istek için ayrı bir bağlantı kurar.

Her bir istek, hedef client tarafından anlaşılmak için HTTP tanımlayıcı başlık (header) alanlarını kendi içerisinde barındırır. Bu tanımlamalar ilk tekrardan yorumlandığı için ve daha önce de bahsettiğimiz gibi her bir istek için bağlantı kurulduğu için gecikmenin yaşanması muhtemeldir.

Küçükte olsa gecikme olduğundan ötürür bu kullanım real-time bir senaryoyu destekleyemeyeceğinden HTTP protokolü yetersiz kalmaktadır.

İşte WebSocket real-time ihtiyacından ötürü HTTP ye alternatif bir çözüm olarak ortaya çıkmıştır.

Not: Real-Time uygulamalar olarak “chat, multiplayer oyunlar, borsa anlık takip uygulamaları vb.” kullanımlar örnek olarak verilebilir.

WebSocket, ilk olarak 2008 yılında Ian Hickson tarafından geliştirilmeye başlanmıştır. Ancak, WebSocket protokolü resmi olarak IETF (Internet Engineering Task Force) tarafından standart hale getirilmeden önce bir dizi geliştirme ve revizyon sürecinden geçmiştir.

WebSocket’in resmi olarak standartlaştırıldığı tarih, IETF’in RFC 6455 belgesinin 2011 yılında kabul edildiği tarihtir. Bağlantıya tıklayarak dökümana göz gezdirebilirsiniz. :)

2 ) WebSocket i niçin kullanmalıyız ?

Eğer bir real-time çalışacak bir çözüme ihtiyacımız var ise bunun için WebSocket i tercih edebiliriz.

Aşağıda bazı avantajlarından bahsedelim:

  1. Gerçek Zamanlı İletişim: WebSocket, gerçek zamanlı iletişimde önemli bir rol oynar. Geleneksel HTTP, istemcinin sunucuya sürekli olarak yeni istekler göndermesini gerektirir ve sunucu bu isteklere yanıt verir. Bu model, gerçek zamanlı etkileşimde gecikmelere ve sürekli olarak yeni istekler oluşturulmasına neden olabilir. WebSocket ise bir bağlantı üzerinden sürekli iletişim sağlar, bu da anlık güncellemeler ve etkileşimlerin hızlı bir şekilde gerçekleşmesine imkan tanır.
  2. Düşük Gecikme: Geleneksel HTTP bağlantıları her bir isteğin yeni bir bağlantı kurma ve kapatma işlemi içermesi nedeniyle gecikmelere yol açabilir. WebSocket, tek bir bağlantı üzerinden sürekli veri transferine izin verir, bu da gecikmeleri azaltır. İletişim kanalı sürekli açık olduğu için veri iletimi daha hızlı ve etkili bir şekilde gerçekleşir.
  3. Etkin Kaynak Kullanımı: WebSocket bağlantıları sürekli açık kalmaya eğilimlidir. Bu, her bir isteğin yeni bir bağlantı kurma ve kapatma sürecine gerek olmadığı için kaynak kullanımını daha etkin hale getirir. Ayrıca, WebSocket üzerinden iletilen veri paketleri daha küçük olabilir, bu da genel verimliliği artırabilir.
  4. İsteğe Bağlı Mesajlaşma: WebSocket, isteğe bağlı olarak mesajlaşma sağlar. Bu, her iki tarafın, yani istemci ve sunucunun, birbirlerine veri göndermelerini sağlar. Bu esneklik, uygulama geliştiricilerine ihtiyaçlarına uygun bir şekilde iletişim kurma imkanı sunar.
  5. İki Yönlü İletişim: WebSocket, iki yönlü iletişimi destekler. Hem istemci hem de sunucu, bağlantı üzerinden birbirlerine veri gönderebilirler. Bu, kullanıcının bir uygulama aracılığıyla etkileşimde bulunmasını ve bu etkileşimlere anında yanıt almasını sağlar.
  6. Verimli Güncellemeler: WebSocket, sunucudan gelen veriyi anlık olarak işleyebilir. Bu özellik, web uygulamalarının dinamik içeriklerini güncellemesi ve kullanıcı arayüzünü sürekli olarak yeniden çizmesi için oldukça önemlidir. Bu, kullanıcı deneyimini iyileştirir ve daha etkileşimli uygulamaların geliştirilmesine olanak tanır.

3) Web Socket Kullanımı (Örnek)

Bundan sonraki kısımda bir WebSocket bağlantısının(handshake adımı) nasıl sağlandığını ve nasıl iletişim kurulduğunu inceleceğiz. Bunu yaparken de sadelik açısından ayrı bir kütüphane kullanmadan pure Javascript ve ASP Net Core ile birlikte gelen System namespace inde var olan yöntemleri kullanacağız.

HANDSHAKE

WebSocket bağlantısının kurulması için (tarayıcı üzerinden düşünelim) ilk adımın tarayıcı tarafından başlatılması gerektiğini bildiğimizden bu ilk isteğin HTTP protokolü ile yapılması gerektiğini biliriz. Yani ilk WebSocket kullanım isteği HTTP protokolü ile yapılır. Bu ilk istek GET methodu ile olup “Upgrade” ve “Connection” Header larına belirli değerler geçilerek yapılır.

İlk isteği biraz daha yakından inceleyelim :)

Makale devamında bağlantı linkini paylaştığım projeden örnek olarak client(browser) dan çıkan ilk handshake isteğine bakalım.

İlk istek (Client Request Messsage)

Mozilla developer Tools Network Tabı

Upgrade Header:

Request Headerlarından Upgrade Header ının websocket olarak ayarlandığına dikkat edelim. Bu bilgi ile Http protokolüyle başlayan iletişim sürecinin bir sonraki isteklerde websocket protokolü ile devam etme isteğini client server a bildiriyor.

Connection Header:

Connection Header değerinin de Upgrade olarak ayarlandığını ve Protokolün yüklseltilmek istendiğini belirtiyoruz. Bu bilgi ile akabinde Upgrade Header da değer olarak belirtilen protokol dikkate alınır.

Sec-WebSocket-Key Header:

Bu Header değer client tarafından oluşturulmuş rastgele bir değer içerir. Güvenliği sağlamak için bu değer sunucu tarafından kullanılır. Bu değer ile server(sunucu) kendi yanıtını oluşturup client a isteğin kabul edildiğini belirtir. Bu yanıtı ise Response Header larında gördüğümüz Sec-WebSocket-Accept Header ı ile gönderir.

Client Kod Örneği (JavaScript)

Client tarafında WebSocket için yazılan bir çok kütüphane mevcut. Ama base pure Javascript kullanarak daha anlaşılır olacağına inandığımdan Javascript bünyesinden bulunan WebSocket API sini kullanmak istedim.

const socket = new WebSocket("ws://exaple.com:8080");

Yukarıda WebSocket nesnesi oluşturulduğu anda handshake adımı otomatik olarak başlamış oluyor. ws ile başlamış olması websocket protokolü ile bağlantının hangi url(exaple.com:8080) üzerinden ilerleyeceği belirtilmiş oluyor. Ama yukarıda belirtilen ilk istek http protokolü ile aynı url üzerinden yapılır.

WebSocket Event Methodları:

Open:

WebSocket handshake adımı tamamlanıp kalıcı bağlantı oluştuğunda tetiklenen event ı yakalayan methoddur.

socket.onopen = () => {
console.log("Connected to the server");
// Your logics or initializers
};

Message:

Eğer server dan gelen bir mesaj var ise tetiklenen event ı yakalayan (handling) metoddur.

socket.onmessage = (event) => {
//"Event handling for messages received from the server."
console.log("Message From Server: " + event.data);
};

Close:

WebSocket bağlantısı kapandığı an tetiklenen event ı yakalayan metoddur.

socket.onclose = (event) => {
// "Event triggered when the socket connection is closed."
if (event.wasClean) {
console.log(`Connection closed cleanly, code=${event.code}, reason=${event.reason}`);
} else {
console.error("Connection abruptly closed");
}
};

Error:

Süreç içerisinde gerçekleşen herhangi bir hatanın hata objesini alan metoddur.

socket.onerror = (error) => {
// "Event triggered in case of a socket error."
console.error("WebSocket Error: " + error);
};

Send(Method)

WebSocket handshake adımından sonra artık kalıcı bağlantımız üzerinden mesaj gönderebiriliz. Send metodu tam olarak bu işi yapmaktadır :)

function sendMessage() {
// A function that sends the message entered by the user to the server.
const message = messageInput.value;
if (message.trim() !== "") {
socket.send(message);
messageInput.value = "";
}
}

Client tarafında önemli onlan kısımları bitirdik. Buraya kadar okudaysınız bir o kadar da eğlenceli olan Server Side tarafına bakalım. :)

Başlıyoruz…

Server Adımı (ASP .Net Core Console Application)

Client tarafından websocket in bağlantısının sağlanması için bir ön isteğin http protokolü ile Javascript WebSocket nesnesi aracılığı ile gönderildiğini söylemiştik. Burada HTTP 1.1 ile Get isteğini server ın yakalayabiliyor olması lazım. Ve bunu sadece bir client için değil gelebilecek her client için yabilmesi lazım. Ama bir limit varsa da onu onu kendiniz de bir condition (if / else) ekleyerekte sağlayabilirsiniz. :)

Dinleme(Request Listener) ihtiyacı için yardımımıza System.Net.Sockets namespace inde yer alan TcpListener sınıfı yetişiyor.

TcpListener sınıfı, TCP/IP protokolünü kullanarak belirli bir IP adresi ve port numarasında bir TCP dinleme (listening) noktası oluşturan bir sınıftır.

`Bağlantı Dinleme` (Listening for Connection): Belirtilen IP adresi ve port numarasında bir TCP dinleme noktası oluşturur.

`Bağlantı Bekleme` (Accepting Connection): Oluşturulan dinleme noktası üzerinden gelen bağlantıları bekler ve kabul eder.

Console uygulamamızda bir server ı simule edecek sınfımız olan WebSocketServer nesnemizi oluşturalım. Oluşturulması listener işlemlerinin başlaması bizim için yeterli olacaktır.

namespace WebSocketServer.Demo {
class Program {
static void Main(string[] args) {
// Application starting
_ = new WebSocketServer();
}
}
}
namespace WebSocketServer.Demo {
private TcpListener? tcpListener;
class WebSocketServer {
public WebSocketServer(){
// Let's start the TcpListener.
StartTcpListener();
// Let's wait for new clients
AcceptNewClient();
}
...
private void StartTcpListener (){
tcpListener = new TcpListener(IPAddress.Any, 8080);
tcpListener.Start();

Console.WriteLine("Server started. Waiting for connections...");
}

private void AcceptNewClient(){
while(true) {
if(tcpListener == null){
break;
}
TcpClient tcpClient = tcpListener.AcceptTcpClient();
ClientHandler clientHandler = new ClientHandler(tcpClient, this);

clients.Add(clientHandler);

Thread clientThread = new Thread(new ThreadStart(clientHandler.StartListening));
clientThread.Start();
}
}
}
...
}

StartTcpListener:

TcpListener ile dinleme noktasını başlatan metoddur. TcpListener objesi ana process (console app) sonlanana kadar yaşar.

AcceptNewClient:

Acception Connection durumunda istekte bulunan yeni bir client kullanıcısını kabul eder ve TcpClient olarak olarak ClientHandler a kullanılmak üzere sunar. Böylece her yeni client için ClientHandler ile handling, listening, broadcastmessage gibi özellikler sunulmuş olur.

Aşağıda console uygulamamızın her bir yeni client için tcpListener ile nasıl beklediğini ve gelen istekte daha önce bahsettiğimiz Headerları görebilirsiniz :)

Proje : https://github.com/mek-12/WebSocketDemo

Keyifli okumalar :)

--

--