WebSocket على Go: إنشاء تطبيقات الوقت الفعلي المتقدمة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: ما وراء WebSocket البسيط على Go



عادةً ما تُظهر أمثلة WebSocket الأساسية على Go اتصال صدى بسيط. في مشاريع الإنتاج الحقيقية - من محطات التداول إلى الألعاب متعددة اللاعبين وأنظمة الإشعارات - هناك حاجة إلى أكثر من ذلك بكثير: إدارة الغرف، الإغلاق السلس، التوسع، ومعالجة الأخطاء بشكل صحيح. في هذه المقالة، سنقوم بتحليل نمط متقدم لبناء تطبيقات الوقت الفعلي على Go باستخدام مكتبة gorilla/websocket.



سنقوم بإنشاء بنية تعتمد على Hub (الموزع المركزي) و Client (الاتصال الفردي)، وإضافة دعم للغرف، وآلية لتحمل الأخطاء، وإظهار كيفية إنهاء عمل الخادم بشكل صحيح.



بنية Hub و Client: أساس خادم الوقت الفعلي



لماذا Hub؟

كل عميل WebSocket هو goroutine منفصل. إدارتها مباشرة من معالج HTTP أمر خطير: يؤدي إلى سباقات البيانات وتسرب الذاكرة. يحل نمط Hub المشكلة من خلال العمل كقناة واحدة للتسجيل والحذف وإرسال الرسائل.



تنفيذ Hub

package main

import ( "log" "sync")

type Client struct { hub *Hub send chan []byte room string}

type Hub struct { clients map[*Client]bool broadcast chan Message register chan *Client unregister chan *Client mu sync.RWMutex}

type Message struct { Room string Data []byte Sender *Client}

func NewHub() *Hub { return &Hub{ clients: make(map[*Client]bool), broadcast: make(chan Message, 256), register: make(chan *Client), unregister: make(chan *Client), }}

func (h *Hub) Run() { for { select { case client := <-h.register: h.mu.Lock() h.clients[client] = true h.mu.Unlock() log.Printf("تم توصيل العميل. الإجمالي: %d", len(h.clients))

case client := <-h.unregister: h.mu.Lock() if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } h.mu.Unlock()

case message := <-h.broadcast: h.mu.RLock() for client := range h.clients { // إرسال فقط إلى الغرفة المطلوبة if client.room == message.Room || message.Room == "" { select { case client.send <- message.Data: default: // إذا كانت القناة ممتلئة - افصل العميل h.mu.RUnlock() h.unregister <- client h.mu.RLock() } } } h.mu.RUnlock() } }}


النقاط الرئيسية:

  • القنوات - register، unregister، broadcast - تقوم بمزامنة goroutines بأمان.
  • RWMutex - يسمح بقراءة قائمة العملاء في وقت واحد، ولكنه يمنع الكتابة.
  • التوجيه القائم على الغرفة - يتم إرسال الرسالة فقط للعملاء في نفس الغرفة.


إدارة الغرف والاشتراكات



الغرف (Rooms) هي مجموعات منطقية من العملاء. على سبيل المثال، في الدردشة، لكل محادثة غرفتها الخاصة. في Hub الخاص بنا، يتم تعيين الغرفة بواسطة حقل room في Client. دعنا نرى كيف يشترك العميل في غرفة.



معالج HTTP مع ترقية WebSocket

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

var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true // للإنتاج، استبدل بالتحقق من الأصل },}

func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err !=

المدونات

توصيات الكتب