لماذا WebSockets هي السحر الذي يجب عليك تجربته
\n\nتخيل: لقد فتحت موقعًا لأسعار العملات الرقمية. الأسعار تقفز كل ثانية. أو دردشة عبر الإنترنت حيث تصل الرسائل فورًا، دون الحاجة إلى "تحديث الصفحة". كيف يعمل هذا؟ في السابق، كان المتصفح يطلب من الخادم باستمرار: "هل هناك شيء جديد؟" - وكان الخادم يرد: "لا، اذهب للنوم". وهذا ما يسمى HTTP polling. إنه بطيء، يستهلك النطاق الترددي، ويُثقل الخادم.
\n\nWebSockets تشبه قناة اتصال مفتوحة. يمكن للخادم نفسه أن يقول للعميل: "انظر، هناك تحديث!" - دون طلبات إضافية. في C#، العمل مع WebSockets ليس فقط مريحًا، بل أنيقًا. توفر بيئة .NET أدوات جاهزة: من الفئات الأصلية System.Net.WebSockets إلى SignalR القوي.
في هذه المقالة، لن نتحدث فقط عن النظرية. سنكتب مشروعين حقيقيين: دردشة الوقت الفعلي ومراقب الأسواق المالية. سترى كيفية إنشاء خادم WebSocket C# وتوصيل عميل به. هيا بنا!
\n\nما هي WebSockets ولماذا C# هي الخيار الأمثل
\n\nWebSocket هو بروتوكول اتصال ثنائي الاتجاه عبر TCP. بعد المصافحة (handshake)، يبقى الاتصال مفتوحًا. تتدفق البيانات في كلا الاتجاهين دون رؤوس HTTP. وهذا يوفر:
\n\n- \n
- السرعة - زمن استجابة بالمللي ثانية. \n
- توفير الموارد - اتصال واحد بدلاً من مئات الطلبات. \n
- وقت فعلي حقيقي - الخادم هو من يبدأ الإرسال. \n
C# في هذا السياق هي مدفعية ثقيلة حقيقية. ASP.NET Core يدعم WebSockets بشكل مدمج. بالإضافة إلى أن البرمجة غير المتزامنة (async/await) تتناسب تمامًا مع نموذج العمل مع القنوات. أنت لا تحظر الخيط أثناء انتظار الرسالة - وهذا يجعل الكود فعالاً وقابلاً للقراءة.
\n\nالمشروع الأول: دردشة الوقت الفعلي باستخدام WebSockets
\n\nلنبدأ بالكلاسيكيات - الدردشة. إنها توضح بوضوح الآلية بأكملها: الاتصال، الإرسال، الاستلام، وإغلاق الاتصال.
\n\nالخطوة 1: إنشاء خادم WebSocket بلغة C#
\n\nافتح Visual Studio أو الطرفية. أنشئ مشروع ASP.NET Core Web API جديد (أو فارغ). قم بتثبيت الحزمة إذا لزم الأمر:
\n\ndotnet add package Microsoft.AspNetCore.WebSockets\n\nالآن في Program.cs نقوم بتكوين الوسيطة (middleware). إليك الحد الأدنى من كود الخادم:
var builder = WebApplication.CreateBuilder(args);\nbuilder.Services.AddWebSockets(options => { });\nvar app = builder.Build();\n\napp.UseWebSockets();\n\n// قائمة لتخزين جميع العملاء المتصلين\nvar clients = new List<System.Net.WebSockets.WebSocket>();\n\napp.Map("/chat", async (HttpContext context) =>\n{\n if (context.WebSockets.IsWebSocketRequest)\n {\n var webSocket = await context.WebSockets.AcceptWebSocketAsync();\n clients.Add(webSocket);\n Console.WriteLine("تم توصيل عميل جديد!");\n\n // مخزن مؤقت لاستقبال البيانات\n var buffer = new byte[1024 * 4];\n while (webSocket.State == WebSocketState.Open)\n {\n var result = await webSocket.ReceiveAsync(\n new ArraySegment<byte>(buffer), CancellationToken.None);\n \n if (result.MessageType == WebSocketMessageType.Close)\n {\n await webSocket.CloseAsync(\n WebSocketCloseStatus.NormalClosure, \n "تم إغلاق الاتصال", CancellationToken.None);\n clients.Remove(webSocket);\n Console.WriteLine("تم فصل العميل.");\n }\n else if (result.MessageType == WebSocketMessageType.Text)\n {\n // استلام رسالة من عميل واحد\n var message = System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);\n Console.WriteLine($"تم الاستلام: {message}");\n\n // إرسالها لجميع العملاء الآخرين\n v