سنعمل في هذا المقال على تطوير خادم TCP متزامن يقوم بإنشاء أرقام عشوائية باستخدام حوالي 65 سطرًا من كود Go، إذ سأشرح كيفية تطوير خادم TCP متزامن، بلغة البرمجة Go، والتي تقوم بإرجاع أرقام عشوائية. إن لم تقرأ المقال السابق حول إنشاء كلمات مرور عشوائية وآمنة في Go، فننصحك بالرجوع إليه وقراءته أولًا.
تعمل خوادم TCP و UDP بخدمة عملاء الشبكة في كل مكان عبر شبكات TCP / IP. لكل اتصال وارد من عميل TCP، سيقوم خادم TCP ببدء تشغيل goroutine جديد لمعالجة هذا الطلب.
تستطيع إيجاد هذا المشروع concTCP.go على GitHub.
التعامل مع اتصالات TCP
يمكنك العثور على منطق البرنامج في دالة ()handleConnection
بلغة Go، والذي يتم تنفيذه على النحو التالي:
func handleConnection(c net.Conn) { fmt.Printf("Serving %s\n", c.RemoteAddr().String()) for { netData, err := bufio.NewReader(c).ReadString('\n') if err != nil { fmt.Println(err) return } temp := strings.TrimSpace(string(netData)) if temp == "STOP" { break } result := strconv.Itoa(random()) + "\n" c.Write([]byte(string(result))) } c.Close() }
إذا أرسل عميل TCP سلسلة التعليمات "STOP"، فسيتم إنهاء برنامج Go أي goroutine الذي يخدم عميل TCP محدد؛ وإلا، سيرسل خادم TCP رقمًا عشوائيًا إلى عميل TCP.
تضمن الحلقة for
أن عميل TCP سيتم خدمته طالما يُتَطلب ذلك. تقرأ الحلقة for
الموجودة في كود Go البيانات من عميل TCP سطرًا بسطر باستخدام ('bufio.NewReader(c).ReadString('\n
وتُعيد إرسال البيانات باستخدام (((c.Write([]byte(string(result
.
التزامن
تنفيذ دالة ()main
، يُعطي أمرًا لخادم TCP لبدء تشغيل برنامج goroutine جديد في كل مرة يتعين عليه خدمة عميل TCP:
func main() { arguments := os.Args if len(arguments) == 1 { fmt.Println("Please provide a port number!") return } PORT := ":" + arguments[1] l, err := net.Listen("tcp4", PORT) if err != nil { fmt.Println(err) return } defer l.Close() rand.Seed(time.Now().Unix()) for { c, err := l.Accept() if err != nil { fmt.Println(err) return } go handleConnection(c) } }
أولاً، تتأكد ()main
من أن البرنامج يحتوي على وسيطة سطر أوامر واحدة على الأقل.
لاحظ أن الكود الموجود لا يتحقق مما إذا كانت وسيطة سطر الأوامر المحددة هي رقم مَنفذ TCP صالح أم لا. ومع ذلك، إذا لم تكن القيمة المحددة رقم منفذ TCP صالحًا، فسوف يفشل استدعاء ()net.Listen
مع ظهور رسالة خطأ مشابهة لما يلي:
$ go run concTCP.go 12a listen tcp4: lookup tcp4/12a: nodename nor servname provided, or not known $ go run concTCP.go -10 listen tcp4: address -10: invalid port
يتم استخدام استدعاء ()net.Listen
لإخبار برنامج Go بقبول اتصالات الشبكة وبالتالي كخادم. قيمة الإرجاع ()net.Listen
هي من النوع net.Conn، والتي تنفذ واجهات io.Reader و io.Writer.
تقوم الدالة ()main
أيضًا باستدعاء الدالة ()rand.seed
لتهيئة مُنشئ الأرقام العشوائية.
أخيرًا، تُتيح حلقة for للبرنامج الحفاظ على قبول عملاء TCP الجدد باستخدام ()accept
والتي سيتم معالجتها بواسطة نسخ الدالة ()handleConnection
، والتي يتم تنفيذها على شكل goroutines.
أول معامل للدالة ()net.Listen
يُحدد المعامل الأول من الدالة ()net.Listen نوع الشبكة التي سيتم استخدامها، بينما يُحدد المعامل الثاني عنوان الخادم بالإضافة إلى رقم المَنفذ الذي سيستمع إليه الخادم.
القيم الصالحة للمُعامل الأول هي:
tcp, tcp4 (IPv4-only), tcp6 (IPv6-only), udp, udp4 (IPv4- only), udp6 (IPv6-only), ip, ip4 (IPv4-only), ip6 (IPv6-only), Unix (Unix sockets), Unixgram, Unixpacket
فعالية خادم TCP المتزامن
يتطلب concTCP.go وسيطة سطر أوامر واحدة، وهي رقم المَنفذ الذي سيستمع إليه. سيكون الناتج الذي ستحصل عليه من concTCP.go عند خدمة عملاء TCP مشابهًا لما يلي:
$ go run concTCP.go 8001 Serving 127.0.0.1:62554 Serving 127.0.0.1:62556
يمكن لناتج (1)netStat التحقق من أن concTCP.go يخدم العديد من عملاء TCP أثناء الاستماع لمزيد من الاتصالات:
$ netstat -anp TCP | grep 8001 tcp4 0 0 127.0.0.1.8001 127.0.0.1.62556 ESTABLISHED tcp4 0 0 127.0.0.1.62556 127.0.0.1.8001 ESTABLISHED tcp4 0 0 127.0.0.1.8001 127.0.0.1.62554 ESTABLISHED tcp4 0 0 127.0.0.1.62554 127.0.0.1.8001 ESTABLISHED tcp4 0 0 *.8001 *.* LISTEN
يعلمنا السطر الأخير من ناتج الأمر السابق أن هناك عملية تستمع إلى المَنفذ 8001، مما يعني أنه لا يزال بإمكانك الاتصال بمنفذ TCP رقم 8001. يتحقق أول سطرين من وجود اتصال شبكة TCP ثابت يستخدم أرقام المنافذ 8001 و 62556. وبالمثل، يتحقق السطران الثالث والرابع من وجود اتصال TCP آخر يستخدم أرقام المنافذ 8001 و 62554.
تُظهر هذه الصورة ناتج concTCP.go عند خدمة العديد من عملاء TCP:
بشكل مشابه، تُظهر الصورة التالية الناتج من عميلين من TCP يتم تنفيذهما باستخدام (1)nc:
يُمكنك ايجاد معلومات أكثر عن (1)nc، والتي تُدعى أيضًا (1)netcat على ويكيبيديا.
الملخص
لقد تعلمت للتو كيفية تطوير خادم TCP متزامن يقوم بإنشاء أرقام عشوائية باستخدام حوالي 65 سطرًا من كود Go، وهو أمر مثير للإعجاب جدًا!
إذا كنت تريد أن يقوم خادم TCP بمهمة مختلفة، فقط قم بتغيير تنفيذ الدالة ()handleConnection.
ترجمة وبتصرّف للمقال Build a concurrent TCP server in Go، لصاحبه Mihalis Tsoukalos.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.