WebSocket على C#: مشاريع حقيقية وتقنيات متقدمة

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

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

ابدأ الدورة

WebSocket على C#: من النموذج الأولي إلى الإنتاج — تقنيات متقدمة لتطبيقات الوقت الفعلي

\n\n

الحلول القياسية لـ WebSocket على C# باستخدام مكتبات مثل System.Net.WebSockets أو SignalR تحل المشاكل الأساسية للدردشات والإشعارات. ومع ذلك، عندما تتجاوز المتطلبات "Hello, World"، يواجه المطور الحاجة إلى التوسع، وضمان الأمان، والتوجيه المخصص، وتحسين الأداء. في هذه المقالة، سنستعرض التقنيات المتقدمة للعمل مع WebSocket في .NET والتي ستسمح لك ببناء أنظمة وقت فعلي موثوقة وعالية التحميل.

\n\n

1. بنية خادم WebSocket قابل للتوسع: الأنماط والتجميع

\n\n

أحد القيود الرئيسية لـ WebSocket القياسي هو ربط الاتصال بمثيل عملية معين. عند التوسع (الأفقي)، لن تصل الرسالة المرسلة إلى الخادم A إلى العميل المتصل بالخادم B. لحل هذه المشكلة، يتم استخدام نهجين:

\n\n
    \n
  • الخلفية المركزية (Backplane): استخدام Redis Pub/Sub أو RabbitMQ أو Azure SignalR Service لتبادل الرسائل بين الخوادم.
  • \n
  • الجلسات الثابتة (Sticky Sessions): يقوم موازن التحميل بتوجيه طلبات العميل دائمًا إلى نفس الخادم. طريقة أقل موثوقية، حيث يفقد جميع عملاء العقدة الاتصال عند تعطلها.
  • \n
\n\n

لنلقِ نظرة على مثال لتنفيذ خلفية مخصصة على Redis باستخدام StackExchange.Redis و System.Net.WebSockets.

\n\n
using StackExchange.Redis;\nusing System.Net.WebSockets;\nusing System.Text;\n\npublic class RedisBackplaneManager\n{\n    private readonly ConnectionMultiplexer _redis;\n    private readonly ISubscriber _subscriber;\n    private readonly ConcurrentDictionary<string, WebSocket> _connections;\n\n    public RedisBackplaneManager(string redisConnectionString)\n    {\n        _redis = ConnectionMultiplexer.Connect(redisConnectionString);\n        _subscriber = _redis.GetSubscriber();\n        _connections = new ConcurrentDictionary<string, WebSocket>();\n        \n        // الاشتراك في القناة "websocket:messages"\n        _subscriber.Subscribe("websocket:messages", (channel, message) => {\n            var data = Encoding.UTF8.GetString(message);\n            // تحليل الرسالة (نفترض التنسيق: "connectionId:payload")\n            var parts = data.Split(':', 2);\n            if (parts.Length == 2 && _connections.TryGetValue(parts[0], out var ws))\n            {\n                ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(parts[1])), \n                    WebSocketMessageType.Text, true, CancellationToken.None);\n            }\n        });\n    }\n\n    public async Task SendToClientAsync(string connectionId, string message)\n    {\n        // النشر في Redis ليتم استلام الرسالة من قبل جميع الخوادم\n        var payload = $"{connectionId}:{message}";\n        await _subscriber.PublishAsync("websocket:messages", payload);\n    }\n\n    public void AddConnection(string id, WebSocket ws) => _connections.TryAdd(id, ws);\n    public void RemoveConnection(string id) => _connections.TryRemove(id, out _);\n}
\n\n

2. بروتوكول مخصص وتوجيه: WebSocket كنقل RPC

\n\n

غالبًا ما تكون هناك حاجة ليس فقط لإرسال النص، بل لاستدعاء الإجراءات عن بُعد (RPC) عبر WebSocket. بدلاً من تحليل JSON يدويًا والتحقق من الأوامر، يمكن بناء موجه رسائل بسيط. يُستخدم هذا النهج داخل SignalR، ولكن يمكنك تنفيذه للتحكم الكامل.

\n\n
public class WebSocketRouter\n{\n    private readonly Dictionary<string, Func<string, Task>> _routes = new();\n\n    public void On(string action, Func<string, Task> handler)\n    {\n        _routes[action] = handler;\n    }\n\n    public async Task RouteAsync(string rawMessage)\n    {\n        // نتوقع تنسيق                

المدونات

توصيات الكتب