WebSocket: Gerçek Zamanlı İletişim

demironW47
4 min readJul 30, 2023

--

src

WebSocket sunucu ve istemci arasında çift yönlü etkileşimli bir bağlantı oluşturmak için geliştirilmiştir. Veri iletiminin çift yönlü (full duplex) olması sayesinde sürekli değişen verileri çekmek için sunucuya sürekli istek atmak gerekmez.

  • Anlık sohbet uygulamaları
  • Finans ve Ticaret uygulamaları
  • Internet of Things cihazları
  • Çevrimiçi çok oyunculu oyunlar
  • İnteraktif uygulamalar: gerçek zamanlı anket vs.

gibi gerçek zamanlı veri transferine ihtiyaç duyulan uygulamalarda kullanılan bir iletişim protokolüdür.

Client tarafında JavaScript kullanacağız. WebSocket API’nin bize sağlamış olduğu servisi kullanarak bir instance oluşturduğumuzda handle etmemiz gereken 4 tane event var.

  • onopen: Bağlantı gerçekleştiği anada tetiklenir.
  • onclose: Bağlantı sonlandırıldığında tetiklenir.
  • onerror: Bağlantı esnasında hata olması durumunda tetiklenir.
  • onmessage: Sunucudan veri geldiğinde tetiklenir.

HTTP

HTTP protokolü için stateless olduğu ifadesini eminim duymuşsunuzdur. Bu bize her http isteğinin kendinden önceki ve kendinden sonraki isteklerle arasında herhangi bir ilişki olmadığı, her bir isteğin ayrı ve bağımsız bir olay olarak yönetildiğini anlatır. Bu senaryoda her request response döngüsü için bir tcp bağlantısı açılır ve three way handshake gerçekleştirilir ve response alındığında tcp bağlantısı sonlandırılır. (http1)

HTTP 1.1 ile birlikte gelen Keep-Alive özelliği sayesinde bir tcp bağlantısı birden fazla request-response döngüsünde kullanılmak üzere saklanmaya başlandı.

Yukarıdaki resimden de anlaşılacağı üzere HTTP tek yönlü (half duplex) bir protokoldür. Mesela bir borsa web uygulamasını açtığımızda döviz kurunda sürekli bir değişim olduğunu görürüz, eğer bu değişimi HTTP ile takip etmek isteseydik sürekli olarak sunucuya bir istek yapıp gereksiz bir trafik ve yük oluştururduk.

WebSocket Server

Go dilini kullanarak minik bir örnek yapalım, Bu örnekte elimizdeki ürünün stoğu bitince websocket bağlatısı sayesinde bir bildirim ileteceğiz. Go dilinde websocket bağlantılarıyla çalışmak için gorilla/websocket paketini kullanacağız.

import (
"github.com/gorilla/websocket"
)

var stock = 2

var ws *websocket.Conn

var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
// r.Header.Get("Origin") == "https://medium.com"
return true
},
}

Kullanacağım paketi import ediyorum, bu bağımlılığı projenize çekmek için aşağıdaki komutu kullanabilirsiniz, daha sonra paket düzeyinde 3 tane değişken tanımlıyorum. Bu kısımda stok bilgisi ve websocket bağlantısının referansını tutuyoruz ve son olarak bir upgrader var. Bu yapı bir http bağlantısını websocket bağlantısına yükseltmek için kullanılır. ReadBufferedSize ve WriteBufferedSize alanları gelen mesajı okumak ve yazmak için bellekte ayrılacak olan alanı belirtmek için kullanılıyor, 1024 bayt’lık bir alan ayırdım. CheckOrigin alanında ise default olarak true return eden bir fonksiyon mevcut, burada belirli domainlerin websocket bağlantısını kullanmasına izin verebilirsiniz.

go get github.com/gorilla/websocket
func reduceStock(w http.ResponseWriter, r *http.Request) {
var err error

if stock <= 0 {
err = ws.WriteMessage(websocket.TextMessage, []byte("the stock is empty."))
if err != nil {
log.Fatal(err)
}
err = json.NewEncoder(w).Encode("the stock already empty.")
if err != nil {
log.Fatal(err)
}
} else {
stock = stock - 1
err = json.NewEncoder(w).Encode("the stock has been reduced by one.")
if err != nil {
log.Fatal(err)
}
}
}

Her /reduceStock adresine gidildiğinde stok sayısını 1 eksilten, eğer stok 0 veya daha az ise WebSocket bağlantısı üzerinden “the stock is empty.” mesajını gönderen bir fonksiyon.


func socket(w http.ResponseWriter, r *http.Request) {

var err error
ws, err = upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
}

}

/socket isimli endpointe istek geldiğinde isteği alıp bir WebSocket bağlantısına yükseltmek gerekiyor. Bunun için bir upgrader tanımlamıştık. Burada okuma ve yazmak için kullanacağı arabellek bilgisini tanımladık. Bir WebSocket bağlantısı elde ettik.

func main() {

http.HandleFunc("/socket", socket)
http.HandleFunc("/reduceStock", reduceStock)
log.Fatal(http.ListenAndServe(":8080", nil))

}

/socket ve /reduceStock adreslerine istek geldiğinde hangi metotların call edileceğine dair kodlama yapıldı.

Başlangıç durumunda stoğu 2 olarak belirlemiştim, /reduceStock adresine 2. kez istek attığımda WebSocket bağlantısı ile bağlı olan client’a bir mesaj gönderecek.

Burada bilinmesi gereken bir başka nokta ise WebSocket bağlantısı yapılırken url’in ws://localhost:8080/socket şeklinde olması gerekmektedir. Kodun tamamını incelemek için bu repoya göz atabilirsiniz.

WebSocket bağlantısı yapılırken ws veya wss kullanıldığını görebilirsiniz, bunlar arasındaki fark http ve https arasındaki fark ile aynıdır. wss’te veri şifrelenmiş bir şekilde taşınır. Websocket’e dair daha detaylı bilgiler için RFC dökümanını inceleyebilirsiniz.

Umarım sizler için keyifli bir içerik olmuştur, hepinize az bug’lı geliştirmeler dilerim.

--

--