بناء خادم شبكة بلغة Go: من TCP إلى HTTP في جلسة واحدة

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

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

ابدأ الدورة

لماذا Go هي اللغة المثالية لبرمجة الشبكات؟

\n\n

إذا سبق لك كتابة خادم شبكة بلغة Python (خاصة باستخدام socket أو asyncio)، فأنت تعلم كيف يمكن أن يتحول الكود بسرعة إلى متاهة من دوال الاسترجاع وحلقات الأحداث. Go (Golang) تحل هذه المشكلة على المستوى المعماري: حيث تجعل الـ Goroutines والقنوات العمل غير المتزامن مع الشبكات بنفس سهولة كتابة الكود التسلسلي.

\n\n

في هذا المقال، سنستعرض برمجة الشبكات بلغة Go عمليًا. ستتعلم كيف تبني خلال 15 دقيقة دردشة TCP كاملة، ترسل حزمة UDP، وتشغل خادم HTTP مع توجيه المسارات. جميع الأمثلة قابلة للتشغيل ويمكنك نسخها وتجربتها.

\n\n

الأساسيات: حزمة net وقوتها الخارقة

\n\n

في Go، كل السحر الشبكي موجود في الحزمة القياسية net. توفر واجهة موحدة للعمل مع TCP و UDP و Unix sockets وحتى SSL/TLS. الميزة الرئيسية هي أن دوال Listen و Dial و Accept تعمل بشكل متزامن ولكنها لا تمنع تشغيل البرنامج بأكمله، لأن كل Goroutine خفيف الوزن.

\n\n

لننتقل مباشرة إلى التطبيق العملي.

\n\n

خادم TCP: دردشة في 10 أسطر

\n\n

لننشئ خادم صدى بسيطًا يستقبل الاتصالات ويعيد إرسال ما استلمه. هذا هو الكلاسيكي في برمجة الشبكات بلغة Go.

\n\n
package main\n\nimport (\n    "bufio"\n    "fmt"\n    "net"\n)\n\nfunc handleConnection(conn net.Conn) {\n    defer conn.Close()\n    scanner := bufio.NewScanner(conn)\n    for scanner.Scan() {\n        message := scanner.Text()\n        fmt.Printf("تم الاستلام: %s\\n", message)\n        conn.Write([]byte("صدى: " + message + "\\n"))\n    }\n}\n\nfunc main() {\n    listener, _ := net.Listen("tcp", ":8080")\n    fmt.Println("خادم TCP يعمل على المنفذ :8080")\n    for {\n        conn, _ := listener.Accept()\n        go handleConnection(conn) // كل Goroutine تمثل عميلاً منفصلاً\n    }\n}
\n\n

ماذا يحدث هنا؟

\n
    \n
  • net.Listen("tcp", ":8080") — ينشئ مستمع TCP على المنفذ 8080.
  • \n
  • حلقة for اللانهائية تقبل اتصالات جديدة عبر Accept().
  • \n
  • يتم معالجة كل اتصال في Goroutine منفصلة go handleConnection().
  • \n
  • داخل الدالة، نقرأ الأسطر عبر bufio.Scanner ونرسل الرد.
  • \n
\n\n

شغّل هذا الكود، افتح الطرفية واتصل عبر nc localhost 8080 (أو Putty). أي رسالة ستعود مع البادئة "صدى:". المذهل أن هذا خادم شبكة كامل قادر على خدمة آلاف العملاء دون أي دوال استرجاع.

\n\n

UDP: توصيل سريع بدون ضمانات

\n\n

إذا كان TCP يشبه المكالمة الهاتفية (إنشاء اتصال ثم التواصل)، فإن UDP يشبه البطاقات البريدية: ترسل وتنسى. Go تجعل العمل مع UDP بنفس السهولة.

\n\n

عميل وخادم UDP

\n\n
// الخادم\npackage main\n\nimport (\n    "fmt"\n    "net"\n)\n\nfunc main() {\n    addr, _ := net.ResolveUDPAddr("udp", ":8081")\n    conn, _ := net.ListenUDP("udp", addr)\n    defer conn.Close()\n\n    buffer := make([]byte, 1024)\n    for {\n        n, clientAddr, _ := conn.ReadFromUDP(buffer)\n        message := string(buffer[:n])\n        fmt.Printf("تم الاستلام من %s: %s\\n", clientAddr, message)\n        conn.WriteToUDP([]byte("تم الاستقبال: "+message+"\\n"), clientAddr)\n    }\n}\n\n// العميل\n// في ملف منفصل أو Goroutine:\nconn, _ := net.Dial("udp", "localhost:8081")\ndefer conn.Close()\nconn.Write([]byte("مرحباً، UDP!"))\nbuffer := make([]byte, 1024)\nn, _ := conn.Read(buffer)\nfmt.Println(string(buffer[:n]))
\n\n

الفرق الرئيسي عن TCP:

\n
    \n
  • لا يوجد Accept() — نحن فقط نستمع إلى المنفذ ونقرأ البيانات.
  • \n
  • كل حزمة تأتي مع عنوان المرسل الخاص بها.
  • \n
  • Go تدير التخزين المؤقت تلقائيًا: ReadFromUDP تقرأ الحزمة التالية المتاحة.
  • \n
\n\n

HTTP: خادم ويب فوري

\n\n

الآن بعد أن أتقنت TCP و UDP، حان وقت بناء خادم HTTP. Go تجعل هذا الأمر في غاية السهولة بفضل حزمة net/http.

\n\n

خادم HTTP أساسي مع توجيه المسارات

\n\n
package main\n\nimport (\n    "fmt"\n    "net/http"\n)\n\nfunc mainPage(w http.ResponseWriter, r *http.Request) {\n    fmt.Fprintf(w, "<h1>مرحباً بك في خادم Go!</h1><p>هذه الصفحة الرئيسية.</p>")\n}\n\nfunc apiHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set("Content-Type", "application/json")\n    fmt.Fprintf(w, `{"message": "مرحباً من API", "status": "ok"}`)\n}\n\nfunc main() {\n    http.HandleFunc("/", mainPage)\n    http.HandleFunc("/api", apiHandler)\n    fmt.Println("خادم HTTP يعمل على المنفذ :8082")\n    http.ListenAndServe(":8082", nil)\n}
\n\n

ملاحظات مهمة:

\n
    \n
  • الدالة http.HandleFunc تربط المسارات بالمعالجات.
  • \n
  • كل معالج يستقبل http.ResponseWriter (للكتابة) و *http.Request (للقراءة).
  • \n
  • Go تدير الاتصالات المتزامنة تلقائيًا — كل طلب يعالج في Goroutine منفصلة.
  • \n
\n\n

افتح المتصفح على http://localhost:8082 لترى الصفحة الرئيسية، أو زر http://localhost:8082/api لترى استجابة JSON.

\n\n

الخلاصة: Go تتفوق في الشبكات

\n\n

كما رأيت، Go تجعل برمجة الشبكات سهلة وفعالة بشكل استثنائي. سواء كنت تبني دردشة TCP بسيطة، أو خدمة UDP سريعة، أو خادم HTTP معقد، فإن Go توفر لك الأدوات المناسبة دون تعقيد غير ضروري.

\n\n

الخطوات التالية:

\n
    \n
  • جرب إضافة تشفير TLS باستخدام crypto/tls.
  • \n
  • استخدم gorilla/mux لتوجيه مسارات أكثر تقدماً.
  • \n
  • اختبر أداء خادمك باستخدام أدوات مثل wrk أو hey.
  • \n
\n\n

ابدأ الآن ببناء أول خادم شبكة لك بلغة Go — ستفاجأ بمدى السرعة والسهولة!

المدونات

توصيات الكتب