Yeni Protokoller – Websockets – Websocket nedir

HTML 5 Standartlarıyla hayatımıza giren Websocket nedir?

Websocket ler için galiba ilk söylenecek şey; Real-time / gerçek zamanlı ve full-duplex / iki yönlü bağlantı ihtiyaçlarını karşılamak adına ortaya çıkmış olmaları diyebiliriz.

Uzun zamandır kullandığımız klasik istemci-sunucu mimarisine bakarak devam edecek olursak. “HTTP” protokolünü esas alan “stateless / durum kontrolü yapamayan” ve istemci den sunucuya gidecek her bir istek için yeni bir TCP bağlantısı açmak zorunda olan, sunucu dan istemciye “ancak gelen istek/request e verilebilecek cevap(response)” ile bir bağ kurabilen bir yapımız olduğunu düşünebiliriz.

Biraz daha açacak olursak. Şöyle bir örnekle devam edebiliriz;

  1. Kullanıcı bir tarayıcı açar ve ulaşmak istediği adresi yazar
  2. Tarayıcı TCP üzerinden, gidilmek istenen adrese/IP ye bir TCP bağlantısı kurar
  3. TCP bağlantısı sadece bir bağlantı oluşturmak ve veriyi değiş tokuş etmek için bize bir yöntem sunarken, istemcinin yaptığı isteğin (www.google.com adresini görüntüleme isteği örneğin)  bir web isteği olduğunun anlaşılması için bir kaç eksta işleme daha ihtiyaç duyar.
  4. Tarayıcı, biz bir port bilgisi belirtmesekde önce baglantıya port bilgisini ekler(genelde 80) sonrasında HTTP protokolü gereği bizden sunucuya giden isteğe bazı ekstra bilgileride ekler.
  5. Bu bilgi eklemeyi de bir standart içinde yapar(HTTP protokolü/standartları) ve böylece sunucu bizim ne tür bir istek içinde bulunduğumuzu anlar
  6. Sunucu isteği karşılar, gerekli işlemleri gerçekleştirir ve istemciye cavabı yine aynı standartları kullanarak iletir.(HTTP Response)
  7. Tarayıcı Cevabı alır ve HTTP standarlarıyla TCP üzerinden kurulan bağlantıyı kapatır.
  8. Bundan sonra yapacağımız her istek için bu süreç aynen tekrar eder. Her seferinde yeni bir bağlantı açılır cevap alınır ve bağlantı kapatılır.

Yukarıdaki süreç genel olarak http üzerinde istemci sunucu iletişimini özetlemeye çalışşsada bazı eksik noktalarıda belirtmek de fayda var.

  1.  ilk olarak, klasik http ile kurduğumuz bağlantı “full-duplex / iki taraflı” değildir. İşlemin iki tarafı varmış gibi gözüksede(istemci ve sunucu) , sunucu, ancak istemciden gelen bir isteğe cevap verme durumunda sürece dahil olabilir.(Sunucu, her hangi bir sebebden dolayı istemciye request/istek olmadan bir iletişim kurma imkanına sahip değildir.)
  2. Gerçek zamanlı bir iletişim için, istemcinin sunucuya sürekli “yeni bir şeyler var mı? diye sorması gerekir(yeni bir http request / istek göndermesi)
  3. sunucu sadece tek bir istemciye cevap vermektedir.(diğer istemciler, dğişiklikleri almak için kendi request / isteklerini sunucuya göndermek zorundalar)
  4. Her yeni bağlantı için yeniden bir TCP connection açılır dedik. Hem sunucu hem istemci için yeni bir yük. Özellikle çok yoğun mesajl alış verişi olan sistemler için ciddi bir yük. SSL üzerinden yapılacak bağlantılarda bu yük biraz daha artacaktır.
  5. HTTP istekleri için, hemen hemen her istekle header/başlık bilgisi (boyutu) belli bir seviyenin altına kolay kolay düşmeyecektir. Sadece bir veriyi silmek için , body/gövde de bir “id” bilgisi taşıyan bir isteğin header/başlık bilgisi çoğu zaman body/gövde den daha büyük olabilmekte.

Belki burada aklımıza “HTTP Keep Alive” seçeneği gelebilir. Ama keep alive ile sadece belir li bir süre için aynı TCP bağlantısını kullanırız(15 saniyemiydi?), üstelik bu sadece yukarıdaki sorunlardan TCP bağlantıları açısından biraz kolaylık sağlar. Sunucu hala full-duplex/iki taraflı bir süreç içinde değildir. hem istemci hem sunucu hala http istek/cevap döngsüne bağımlıdır.

fulduplex yada gerçek zamanlı bağlantı ihtiyacı

Gelişen web kullanımı ve bu kullanımla birlikte hayatımıza giren gerçek zamanlı iletişim şekilleri başta olmak üzere bir çok yeni durum oratay çıktı. Örneğin, artık kimse yeni bir e-mail geldimi diye sayfayı yenilememek te. Gmail/Hotmail ekranınız açıkken “yeni bir email aldığınız da”, bu yeni e-mail otomatik olararak size  iletilmekte.

Yada kullanıcın ekran da görüntülediği “Borsa bilgilerini” , hiç bir şey yapmadan,( sayfayı yenilemeden, her hangi bir “yenile” butonuna basarak, bir yeni istek ve cevap sürecini oluşturmadan) ekranın da gerçek zamanlı olarak güncellenmesini istemek de.

Yukarıda bahsettiğimiz(örneğin borsa örneği), “gerçek zamanlı” yada “iki taraflıymış” gibi gözüken bağlantı modeli , şimdiye kadar web için aslında ne gerçekten “Gerçek zamanlı” nede “İki taraflı ” bir iletişim değil di. Bu na benzer bir yapıyı kurmak için aşağıdaki iki alternatiften birini kullanırdık genelde.

  1. polling – İstemci sürekli olarak belirli aralıklarla sunucuya bir istek de bulunur ve yeni bir şey olup olmadığını kontrol eder.
    • Web dünyasını için düşünecek olursak; Javascript ile her 1 dakikada bir Ajax request gönderdiğimizi düşünebiliriz.
  2. long polling – istemci, bir request / isteği sunucuya gönderir
    • Sunucu gelenisteğe “eğer yeni bir şey varsa” hemen cevap verir, eğer yeni bir durum yoksa hemen cevap vermek yerine, bir loop/döngü oluşturarak belli aralıklarla kendi iç sistemini kontroller eder, bu süreç de yeni bir şey olduğu anda istemci ye bu cevabı verir.
    • Bağlantı kapanır, istemci yeniden aynı isteği yapar ve sunucu tekrar aynı süreci gerçekleştirir.

     REST vs WebSockets

İki sistem için de ortak olan bazı problemler e bakacak olursak; iki sistem de “Yeni bir durum / güncelleme” olup olmadığına karar verecek bir yapıya ihtiyac duymakda.

Yine 2 sistem içinde, long-polling için nispeten daha az olsada “sürekli” diyebileceğimiz “istek/cevap, request/response” döngüsü söz konusu. Bu süreklilik gereksiz yere bir çok “request/response” yapılmasına da sebeb olmak da.

Ayrıca, her istemci için “özellikle long polling de” yeni bir durum var mı gibi bir kontrol süreci oluşturulmasıyla uzun süreli bağlantılar, özellikle sunucu tarafına ciddi bir iş yükü getirmekte. Kısacası, çift taraflı ve gerçek zamanlıymış “gibi” duran bu yapının çözülmesi gereken bir çok sorunu var.

Websocket

Şimdi şöyle bir şey düşünün, istemci sadece bir kereliğine sunucuya websocket bağlantısı oluşturmak için http request gönderse, sonra sunucu bunu kabul edip, websocket üzerinden bir baglantıyı istemciye açsa.

Bundan sornasında, istemci ile sunucu arasında full-duplex/iki taraflı bir baglantı köprüsü kurulsa. Sonrasında, ne istemci sürekli olarak “yeni bir şeyler var mı” diye sorsa, ne de sunucu kendi içinde bir döngü kurup sürekli bir kontrol yapmak zorunda olmasa.

Sunucu sadece gerektiği zaman(örneğin veri tabanına bir kayıt eklendiğinde, yada bir hisse senedinin fiyatı değiştiğinde) istemciye bu bilgiyi gönderebilse. Üstelik , sunucu sadece tek bir istemciye değil “1 den çok istemcinin haberdar edilmesi gereken bir durum olduğunda” hepsini bir den haberdar edebilse.

İşte, websocket ler genel olarak bu sorunları çözmek için geliştirilmiş yeni bir iletişim kanalını sağlamaya çalışmaktalar.

     websockets vs rest

Sadece tarayıcılar için olmasada, özelinde ilk hedef olarak tarayıcıların HTTP protokolü dışında diğer başka alternatifleri de kullanarak sunucu ile bağlantı kurmasını ve bu bağlantının bir şekilde açık bırakılıp “istemci ile sunucun çift taraflı/full-dublex ” olarak sürekli(websocketler üzerinden) “gerçek zamanlı/real-time” halinde iletişim de kalmalarını sağlamaya çalışmakta websocket baglantıları.

Websocket iletişimiz için temel olarak iki parçaya ihtiyacımız var;

  1. Websocket desteği olan bir istemci (Örneğin bir tarayıcı-Chrome vs.)
  2. Websocket desteği olan bir sunucu(Örneğin Node.js)

Bu basit yapı ile websocketlerin çözdüğü problemlere bakarak devam edelim.

  • İlk olarak sadece başlangıçda tek bir  TCP bağlantisi kurar sonrasında, aynı bağlantı tüm iletişim için kulanılır.
  • Sadece, ilk ilk bağlantımız için bir header/başlık bilgisi gönderimi sözkonusudur. Sonraki iletşim sürecinde tekrar tekrar gönderime gerek yoktur.
  • Transfer sürecindeki iletişim ağırlığı çok ama çok düşüktür.(2 bytes.) HTTP açısından çok bu hafifliğe ulaşmak imkansız gibi bişeydir.
  • Bağlantı “full-duplex/iki taraflıdır“. Hem sunucu hem istemci aynı bağlantıyı kulanarak iletişimi devam ettirir.
  • Bağlantı, iki taraflı olduğu için sunucu gerek duyduğun da istemciye istediği gibi mesaj yollayabilir .
  • Sunucu gerek duyduğunda, gerekli tüm istemcilere ulaşabileceği için, gerçek zamanlı olarak iletişim sağlanabilir.(İstemci A, veri tabanın da bir kayıdı güncellediğin de, sunucu bu güncellemeyi alması gereken tüm istemcilere ilgili güncellemeyi iletebilir).
HTPP/REST vs Websocket (performans)

Websocket baglantısının anatomisi

WebSockets bağlantılarımız da tıpkı http gibi TCP yi kullanmakta. İlk bağlantı, http ile ile kurulup sonrasın da web socketlere taşınmakta.

Http üzerinden kurulan ilk bağlantıya genelde ” handshake / el sıkışma ” süreci diyoruz. Bu süreç de http üzerinden kurulan bağlantı, karşılık lı antlaşmayla “websocket” lere taşınmaktadır.

Bağlantı websocket üzerine taşındıktan sonra “full-duplex/iki taraflı” olarak bağlantımız açık kalır ve iletişimi websocket ler üzerinden gerçekleştiririz. Aşağıdaki diagrama bakalım:

How it works?

HTTP üzerinden kurulan ilk bağlantının sadece http-headers upgrade / http bağlantısını gerekli bilgileri değiştirip, websocketlere geçisi sağlamak için yapdığımızı görüyoruz.   Bağlantıyı kurmak için yapğtığımız ilk reqeuest / istek şuna benzer bir header/başlık ile istemciden başlar;

Upgrade: websocket 
Connection: Upgrade (isteği bir yükseltme olarak algıla)
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== (tekil bir tanımlayıcı)
Sec-WebSocket-Version: 13
Origin: http://example.com (istemci bilgisi)
sunucu bu header/başlığı görünce, gerekli bağlantı kanalını açar ve istemciye şuna benzer bir cevap verir;

HTTP/1.1

Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

yukarıdaki cevap gördüğünüz gibi, istediğin kabul edildiğini ve bağlantının websocketlere taşındığını göstermekte. Websocket bağlantı sürecininin W3 tarafından açıklanan standartlarına buradan bakabilirsiniz.

W3 standartlarına baktığımızda, gördüğümüz gibi uygulamızın gerçekleştirmesi gereken Interface/Arayüz gayet sade;

[Constructor(in DOMString url, in optional DOMString protocol)]

interface WebSocket { readonly attribute DOMString URL;

// ready state

const unsigned short CONNECTING = 0;

const unsigned short OPEN = 1;

const unsigned short CLOSED = 2;

readonly attribute unsigned short readyState;

readonly attribute unsigned long bufferedAmount;

// networking attribute

Function onopen;

attribute Function onmessage;

attribute Function onclose;

boolean send(in DOMString data);

void close(); };

WebSocket implements EventTarget;

En temel haliyle , Bağlantı yolunu (Url), Bağlantı durumu (Connecting,Closed,Open) , veri boyutunu ve son olarak 2 method(send,close) ve 3 tane callback/handler(onopen, onmessage,onclose) i içeriyor.

URL, ilk bağlantıyı http üzerinden yağtığımız için gerekli. Sonraki süreçte “bağlantı durumu” kontrolleri için değişkenlerimiz var. Sonrasında yönetim ve events/olaylar için tanımladığımız metodlar söz konusu.

send metodu tahmin edebileceğiniz gibi, istemciden sunucuya, sunucudan istemciye mesaj göndermek için kullanılacak. close ise bağlantıyı kapatmak için.

onopen, onmessage,onclose
ise sırasıyla;

  1. onopen: Bağlantı websocketlere taşınıp iletişim için hazır hale geldiğin de kullanabileceğimiz bir callback handler.
  2. onmessage: İstemciden sunucuya yada sunucudan istemciye  gönderilen mesajların işlenmesi için kullanılacak callback handler
  3. onclose: bağlantı kapandığında çalışacak callback handler.

Videoda bu konuları örneklendirmeye çalıştığım için burada daha fazla değinemedim. Umarım websocket mimarisini anlamak adına faydalı bir yaız olmuştur.

Son olarak, gerçek hayatta, websocketleri kullanan uygulamalar geliştirmek için, (teknik olarak zorunlu olmasada) Socket.io ve SignalR gibi yardımcı kütüphaneleri kullanacağımız için bu iki kütüphane ile ilgili bir kaç yazı daha yazamaya çalışacağım.

Video – Websocketlere genel bakis;

[fvplayer src=”https://s3.amazonaws.com/yazilimgunluguvideo/websocketgiris.mp4"]

video daki ornek kodlar ;

https://github.com/hdd42/websocket_ornek

Güzel bir örnek

Geçenler de Starwars filmi için yapılan tarayıcı da çalışan  örneği gördünüz mü bilmiyorum, ama yoğun olarak websocket mimarisini kullan bu yapıya bir göz atmanızı tavsiye ederim. https://lightsaber.withgoogle.com/

oyunun mimari yapısı;

 

https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

http://blog.arungupta.me/rest-vs-websocket-comparison-benchmarks/

https://www.pubnub.com/blog/2015-01-05-websockets-vs-rest-api-understanding-the-difference/

https://www.engineyard.com/articles/websocket

Why the REST don’t use WebSockets

4 thoughts on “Yeni Protokoller – Websockets – Websocket nedir

  1. elinize sağlık güzel bir yazı kaleme almışsınız.
    kafama takılan bir konu oldu. websocket uyumlu bir sunucu maksimum kaç istemciye hizmet verebilir. tcp-ip maksimum port sayısı kabaca maksimum 65535. bu sınır nasıl aşılmıştır. yada ben yanlış mı değerlendiriyorum.

    1. Merhaba,
      TCP deki limit (65 bin / IPv4) protokol de tanımlı bir limit yani pratikte “hard/zoraki” bir limit değil aslında, ama bir çok işletim sistemi varsayılan olarak network interfacelerinde bu limite sahip olsalarda bu limiti modifiye etmenize izin verirler.

      Ama bu limit sizin düşündüğününüz şekilde “azami istemci sayısını” kısıtlamayacaktır, çünkü her istemci sabit bir port üzerinden websocket sunucusuna bağlanacak ama farklı olan yani her istemci için açılan şey “yeni bir socket / file descriptor” olacaktır.

      Kısacası 64000/16bit den / Socket => bize şöyle bir hesap çıkartacaktır
      64k connections per incoming IP address on a single local port

      Bir başka önemli konuda, concurent bağlantı meselesi yani 50-60 bin sürekli açık/bağlı istemci sayısını yakalamak çok kolay değil büyük yüksek trafikli firmalar/sunucular dışında. Yani sürekli olarak bağlı istemci sayısı her zaman o seviyede olmaz web socketler için. Ve bizim dikkat etmemiz gerken istemci sayısıda bu “concurent client ” olarak geçen sayıdır.

      Vesselam, azami concurent istemci sayısı port sayısına teorik olarak bağlı iken pratikte tamamen sunucunun kaynaklarına(Ram/CPU) ve kullanılan uygulama geliştrime platformuna bağlıdır. ( C/C++, Node, Java vs.)

      Örneğin

      4ghz i7 4790Ks / 16GB RAM / Ubuntu 16.04 / GB ethernet

      konfigürasyona sahip bir sunucu için
      Nodejs/C++/Go gibi bir dil ile yazılan bir web socket sunucusunun 10/15 bin istemci , ruby/python vs içinde 2/4 bin arası istemci azami olarak düşünelebilir. (bu örnek sadece beklenen olağan performansları yansıtmakta, ve benim gördüğüm en başarılı örnekler “milyon kullanıcı seviyesinde” genelde C/C++ ve sonrasında Erlang ile yazılan web socket sunucuları)
      Kolay Gelsin.

Leave a Reply

Your email address will not be published. Required fields are marked *