تعلم البرمجة مع Python


الدرس: إدارة الشبكات


الصفحة السابقة
موضوع واسع موضوع الشبكات! إذا اضطررت إلى تقديم عرض تفصيلي ، أو حتى التحدث عن الشبكات بشكل عام ، فسوف أحتاج إلى أكثر من مجرد فصل للنظرية فقط.

في هذا الفصل ، سوف نتعلم كيفية جعل تطبيقين يتواصلان بفضل المقابس ، وهي كائنات تسمح للعميل بالاتصال بخادم ونقل البيانات من أحدهما إلى الآخر.

إذا كان هذا لا يجعل فمك يسيل ...

عرض موجز للشبكة



كما قلت أعلاه ، تعتبر الشبكة موضوعًا أكبر من أن أعرضه في فصل واحد. سنركز هنا على فهم كيفية توصيل تطبيقين ، يمكن أن يكونا على نفس الجهاز ولكن أيضًا على الأجهزة البعيدة. في هذه الحالة ، يتصلون عبر الشبكة المحلية أو الإنترنت.

توجد عدة بروتوكولات لاتصالات الشبكة. إذا كنت ترغب في ذلك ، فهذا يشبه إلى حد ما الاتصال الشفوي: لكي تسير عمليات التبادل بسلاسة ، يجب أن يتحدث الطرفان (أو أكثر) الحاضران نفس اللغة. هنا سوف نتحدث عن بروتوكول TCP  .

بروتوكول TCP


يشير اختصار هذا البروتوكول إلى بروتوكول التحكم في الإرسال أو " Transmission Control Protocol" . بشكل ملموس ، فإنه يجعل من الممكن توصيل تطبيقين وجعلهما يتبادلان المعلومات.

يُطلق على هذا البروتوكول "الاتصال الموجه" ، أي أن التطبيقات متصلة بالتواصل وأنه يمكننا التأكد ، عندما نرسل معلومات عبر الشبكة ، من استلامها بواسطة التطبيق الآخر. إذا انقطع الاتصال لسبب ما ، يجب على التطبيقات إعادة إنشاء الاتصال للاتصال مرة أخرى.

قد يبدو هذا واضحًا بالنسبة لك ، لكن بروتوكول مخطط بيانات المستخدم ( UDP ) ، على سبيل المثال ، يرسل معلومات عبر الشبكة دون القلق بشأن ما إذا كان الهدف سيستقبلها أم لا. هذا البروتوكول غير متصل ، يرسل أحد التطبيقات شيئًا ما عبر الشبكة لتحديد هدف. يكفي إذن أن نصلي بشدة حتى تصل الرسالة بشكل صحيح!

والأخطر من ذلك ، أن هذا النوع من البروتوكول مفيد إذا كنت بحاجة إلى تمرير الكثير من المعلومات عبر الشبكة ولكن الفقد البسيط للمعلومات لا يؤدي إلى تعطيل كبير. يوجد هذا النوع من البروتوكول في ألعاب الرسومات المتصلة بالشبكة ، حيث يرسل الخادم بشكل متكرر معلومات إلى العميل بحيث يقوم بتحديث نافذته. هناك الكثير مما يجب نقله ولكنه ليس بالأمر الكبير إذا كان هناك خسارة صغيرة في المعلومات من وقت لآخر ، حيث سيرسل الخادم المعلومات مرة أخرى بعد بضع أجزاء من الثانية.

في غضون ذلك ، فإن بروتوكول TCP هو ما يهمنا. إنه أبطأ قليلاً من UDP ولكنه أكثر أمانًا ، وبالنسبة لكمية المعلومات التي سنرسلها ، فمن الأفضل التأكد من المعلومات التي يتم إرسالها بدلاً من سرعة وصولها.

العملاء والخادم


في البنية التي سنراها في هذا الفصل ، نجد عمومًا خادمًا واحدًا والعديد من العملاء. الخادم هو الجهاز الذي سيعالج طلبات العميل.

إذا قمت بالوصول إلى ArabClassroom ، على سبيل المثال ، فذلك لأن متصفحك ، الذي يعمل كعميل ، يتصل بخادم ArabClassroom . يرسل لهم رسالة تطلب منهم الصفحة التي تريد عرضها ويرسل خادم ArabClassroom ، بلطفهم الكبير ، الصفحة المطلوبة إلى العميل.

هذه البنية شائعة جدًا ، حتى لو لم تكن الوحيدة الممكنة.

في الأمثلة التي سنراها، فإننا سنضع اثنين من التطبيقات: على الخادم تطبيق و العميل تطبيق . لذلك يستمع الخادم أثناء انتظار الاتصالات ويتصل العملاء بالخادم.

الخطوات المختلفة


ستعمل تطبيقاتنا وفقًا لنمط مماثل إلى حد ما. فيما يلي خطوات العميل والخادم بالترتيب. الخطوات مبسطة للغاية ، يمكن لمعظم الخوادم التواصل مع العديد من العملاء ولكننا لن نرى ذلك على الفور.

الخادم :

  1. ينتظر اتصال من العميل ؛
  2. يقبل الاتصال عندما يتصل العميل ؛
  3. تبادل المعلومات مع العميل ؛
  4. يغلق الاتصال.
العميل :
  1. الاتصال بالخادم
  2. تبادل المعلومات مع الخادم ؛
  3. يغلق الاتصال.
كما رأينا ، يمكن للخادم الحوار مع العديد من العملاء: هذا هو بيت القصيد. إذا كان بإمكان خادم ArabClassroom الاتصال بعميل واحد فقط في كل مرة ، فسيتعين عليك انتظار دورك ، ربما لفترة كافية ، قبل الوصول إلى صفحاتك. وبدون خادم يمكنه التحدث إلى العديد من العملاء ، ستكون ألعاب الشبكة أو برامج المراسلة الفورية أكثر تعقيدًا.

قم بتأسيس اتصال



لكي يتصل العميل بالخادم ، نحتاج إلى معلومتين:

  • اسم المضيف   host name)  باللغة الإنجليزية)، والذي يعرف جهاز على شبكة الإنترنت أو الشبكة المحلية. تسمح لك أسماء المضيفين بتمثيل عناوين IP بشكل أكثر وضوحًا (لدينا اسم مثل google.fr، أسهل في التذكر من عنوان IP المقابل 74.125.224.84 ) .
  • رقم المنفذ ، والذي غالبًا ما يكون خاصًا بنوع المعلومات التي سنتبادلها. إذا طلبنا اتصالاً بالويب ، فسيسأل المتصفح عمومًا المنفذ 80عما إذا كان موجودًا http أو المنفذ 443 إذا كان في اتصال آمن ( https) . رقم المنفذ بين 0 و 65535 (لذا يوجد عدد غير قليل!) والأرقام بين 0 و 1023 محجوزة من قبل النظام. يمكنك استخدامها ، لكنها ليست فكرة جيدة جدًا.
بشكل أساسي ، عندما يحاول المستعرض الخاص بك الوصول إلى ArabClassroom ، فإنه ينشئ اتصالًا بالخادم الذي يوجد اسم مضيفه  arabclassroom.com على المنفذ 80 . في هذا الفصل ، من المرجح أن نعمل مع أسماء المضيفين أكثر من استخدام عناوين IP .

المقابس sockets


كما سنرى ، المقابس هي كائنات تسمح لك بفتح اتصال بآلة محلية أو بعيدة والتبادل معها.

يتم تحديد هذه الكائنات في الوحدة النمطية socket وسنرى الآن كيف تعمل.

المقابس sockets



لذلك لنبدأ ، بفرح وروح الدعابة ، باستيراد الوحدة الخاصة بنا socket .


import socket
 
سننشئ خادمنا أولاً ثم ، بالتوازي ، عميلاً. سوف نتواصل مع الاثنين. في الوقت الحالي ، نحن نتعامل مع الخادم.

بناء مقبسنا(socket)


سوف نستخدم المنشئ لهذا الغرض socket . في حالة اتصال TCP ، فإنه يأخذ المعلمتين التاليتين بالترتيب:

  • socket.AF_INET  : عائلة العنوان ، ها هي عناوين الإنترنت ؛
  • socket.SOCK_STREAM : نوع المقبس SOCK_STREAM لبروتوكول TCP .

>>> connexion_principale = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>>
 

قم بتوصيل المقبس (socket)


بعد ذلك ، نقوم بتوصيل المقبس الخاص بنا. بالنسبة لاتصال الخادم ، الذي سينتظر اتصالات من العملاء ، نستخدم الطريقة bind . يتطلب معلمة واحدة: tuple (nome_host, port) .

انتظر لحظة ، اعتقدت أن عميلنا متصل بخادمنا ، وليس العكس ...

نعم ، ولكن لكي يستمع خادمنا على منفذ ، يجب تكوينه وفقًا لذلك. لذلك في حالتنا ، سيكون اسم المضيف فارغًا وسيكون المنفذ كما تريد ، بين 1024 و 65535.


>>> connexion_principale.bind(('', 12800))
>>>
 

استمع إلى مقبسنا(socket)


حسن. المقبس الخاص بنا جاهز للاستماع على المنفذ ، 12800 لكنه لم يستمع بعد. سنحدد أولاً الحد الأقصى لعدد الاتصالات التي يمكنه استقبالها على هذا المنفذ دون قبولها. الطريقة المستخدمة لهذا listen . عادة ما نمرره 5 كمعامل.

هل هذا يعني أن خادمنا سيكون قادرًا على التواصل مع 5 عملاء فقط كحد أقصى؟

لا. هذا يعني أنه في حالة اتصال 5 عملاء ولم يقبل الخادم أيًا من هذه الاتصالات ، فلن يتمكن أي عميل آخر من الاتصال. ولكن عادةً ، بعد وقت قصير جدًا من طلب العميل الاتصال ، يقبله الخادم. حتى تتمكن من الحصول على المزيد من العملاء المتصلين ، لا تقلق.


>>> connexion_principale.listen(5)
>>>
 

قبول اتصال من العميل


أخيرًا ، الخطوة الأخيرة ، سنقبل الاتصال. لم يتم إجراء أي اتصال بعد ، لكن الطريقة accept التي سنستخدمها ستحظر البرنامج طالما لم يتصل أي عميل.

من المهم ملاحظة أن الطريقة accept تُرجع معلومتين:

  • المقبس المتصل الذي تم إنشاؤه للتو ، المقبس الذي سيسمح لنا بالحوار مع عميلنا الذي اتصل للتو ؛
  • مجموعة تمثل عنوان IP الخاص بالعميل ومنفذ الاتصال.
منفذ اتصال العميل ... أليس هو نفس منفذ الخادم؟

لا ، لأن عميلك ، بفتح اتصال ، يمر عبر ما يسمى بمنفذ "الإخراج" الذي سيختاره النظام من بين المنافذ المتاحة. بشكل أساسي ، عندما يتصل العميل بخادم ، فإنه يستعير منفذًا (شكل من أشكال البوابة ، إذا صح التعبير) ثم يقوم بإنشاء الاتصال على منفذ الخادم. لذلك هناك منفذين في حالتنا، لكن المنفذ الذي يستخدمه العميل لفتح اتصاله لن يثير اهتمامنا.


>>> connexion_avec_client, infos_connexion = connexion_principale.accept()
 
هذه الطريقة ، كما ترى ، تعطل البرنامج. إنها تنتظر اتصال العميل. دعنا نترك نافذة Python مفتوحة ، ونفتح الآن نافذة جديدة لبناء عميلنا.

انشاء العميل


ابدأ ببناء المقبس بنفس الطريقة:


>>> import socket
>>> connexion_avec_serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>>
 

قم بتوصيل العميل


للاتصال بالخادم ، سنستخدم الطريقة connect . يأخذ كمعامل tuple ، مثل bind، يحتوي على اسم المضيف ورقم المنفذ الذي يحدد الخادم الذي نريد الاتصال به.

أنت تعرف رقم المنفذ الذي نريد الاتصال به: إنه موجود 12800 . نظرًا لأن تطبيقي Python الخاصين بنا موجودان على نفس الجهاز ، فسيكون اسم المضيف localhost(أي الجهاز المحلي) .


>>> connexion_avec_serveur.connect(('localhost', 12800))
>>>
 
ها أنت ذا ، خادمنا وعميلنا متصلان!

إذا عدت إلى وحدة تحكم Python التي تستضيف الخادم ، يمكنك أن ترى أن الطريقة accept لم تعد محظورة ، لأنها قبلت للتو الاتصال الذي طلبه العميل. لذلك يمكنك إدخال كود على جانب الخادم مرة أخرى:


>>> print(infos_connexion)
('127.0.0.1', 2901)
>>>
 
الجزء الأول من المعلومات هو عنوان IP الخاص بالعميل. هنا هو  127.0.0.1 IP الخاص بالكمبيوتر المحلي. أخبر نفسك أن المضيف يقوم localhost بإعادة التوجيه إلى IP 127.0.0.1 .

والثاني هو منفذ خروج العميل ، والذي لا يهمنا هنا.

توصيل مقبسنا (socket)


الآن ، كيف نجعل مقابسنا تتواصل؟ حسنًا ، باستخدام طرق send الإرسال و  recv الاستلام  .

ستكون المعلومات التي ترسلها سلاسل بايت ، وليس str !

إذن من جانب الخادم:


>>> connexion_avec_client.send(b"Je viens d'accepter la connexion")
32
>>>
 
تقوم الطريقة send بإرجاع عدد الأحرف التي تم إرسالها إليك.

الآن ، من جانب العميل ، سوف نتلقى الرسالة التي أرسلناها للتو. recv تأخذ الطريقة كمعلمة عدد الأحرف المراد قراءتها. عادة ، يتم تمرير القيمة 1024 . إذا كانت الرسالة أكبر من 1024 حرفًا ، فسنسترد الباقي بعد ذلك.

في نافذة Python من جانب العميل:


>>> msg_recu = connexion_avec_serveur.recv(1024)
>>> msg_recu
b"Je viens d'accepter la connexion"
>>>
 
سحر أليس كذلك؟ حقا لا؟ ضع في اعتبارك أنه يمكن استخدام هذه الآلية الصغيرة لجعل التطبيقات تتواصل مع بعضها البعض ليس فقط على الجهاز المحلي ، ولكن أيضًا على الأجهزة البعيدة المتصلة بالإنترنت.

يمكن للعميل أيضا إرسال المعلومات إلى الخادم والخادم يمكنه الحصول عليها، كل ذلك بفضل الطرق sendو recvالتي شهدناها للتو.

اغلق الاتصال


لإغلاق الاتصال ، يجب أن نستدعي الطريقة closeالمقبس الخاص بنا.

جانب الخادم:


>>> connexion_avec_client.close()
>>>
 
ومن جانب العميل:

>>> connexion_avec_serveur.close()
>>>
 
هنا ! سألخص ذلك من خلال إظهار خادم صغير وعميل يمكننا استخدامهما. وأخيرًا ، سأوضح لك طريقة لتحسين خادمنا قليلاً من خلال السماح له بإدارة العديد من العملاء في نفس الوقت.

الخادم



لتجنب الالتباس ، أعطيك هنا كود الخادم ، محسّنًا قليلاً. لا يقبل سوى عميل واحد (سنرى أدناه كيفية قبول عدة عملاء) ويستمر حتى يتلقى الرسالة من العميل fin .

في كل مرة يتلقى فيها الخادم رسالة ، يقوم بإرسالها مرة أخرى '5 / 5' .


import socket

hote = ''
port = 12800

connexion_principale = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connexion_principale.bind((hote, port))
connexion_principale.listen(5)
print("الخادم يستمع الآن على المنفذ {}".format(port))

connexion_avec_client, infos_connexion = connexion_principale.accept()

msg_recu = b""
while msg_recu != b"fin":
    msg_recu = connexion_avec_client.recv(1024)
    # يمكن للتعليمات أدناه طرح استثناء إذا كانت الرسالة
    # المُستقبلة تحتوي احرفا حاصة
    print(msg_recu.decode())
    connexion_avec_client.send(b"5 / 5")

print("إغلاق الاتصال ")
connexion_avec_client.close()
connexion_principale.close()
 
كثيرا للخادم. ستوافقون الرأي ، إنه صغير للغاية ، لكنه عملي. سنرى كيفية تحسينه بعد قليل.

العميل



مرة أخرى ، أقدم لك كود العميل الذي يمكنه التفاعل مع خادمنا.

سيحاول الاتصال بمنفذ 12800 الجهاز المحلي. يطلب من المستخدم كتابة شيء ما على لوحة المفاتيح وإرسال هذا الشيء إلى الخادم ، ثم ينتظر رده.


import socket

hote = "localhost"
port = 12800

connexion_avec_serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connexion_avec_serveur.connect((hote, port))
print("تم إنشاء الاتصال مع الخادم على المنفذ {}".format(port))

msg_a_envoyer = b""
while msg_a_envoyer != b"fin":
    msg_a_envoyer = input("> ")
    # قد يتعطل إذا قمت بكتابة أحرف خاصة
    msg_a_envoyer = msg_a_envoyer.encode()
    # نرسل الرسالة
    connexion_avec_serveur.send(msg_a_envoyer)
    msg_recu = connexion_avec_serveur.recv(1024)
    print(msg_recu.decode()) # مرة أخرى ، يمكن أن تتعطل إذا كانت هناك احرف خاصة

print("إغلاق الاتصال ")
connexion_avec_serveur.close()
 
ما تفعل الوظائف  encode و  decode ؟

Encode هي طريقة str . يمكن أن يأخذ اسم ترميز كمعامل ويسمح بتمرير str سلسلة بايت . إنه ، كما تعلم ، هذا النوع من السلسلة التي  تقبل send . في الواقع ، يقوم encode بترميز السلسلة str وفقًا لترميز دقيق (افتراضي ، Utf-8  ) .

Decode ، على العكس من ذلك ، هي طريقة بايت . يمكن أيضًا أن يأخذ ترميزًا كمعامل ويعيد سلسلة مفككةstr  باستخدام التشفير (افتراضيًا Utf-8  ) .

إذا كان ترميز وحدة التحكم الخاصة بك مختلفًا عن  Utf-8  (غالبًا ما يكون هذا هو الحال في Windows )، فقد تحدث أخطاء إذا كانت الرسائل التي تقوم بتشفيرها أو فك تشفيرها تحتوي على علامات .

ها نحن قد رأينا خادمًا وعميلًا ، كلاهما بسيط للغاية. الآن ، دعنا نرى شيئًا أكثر تفصيلاً!

خادم أكثر تفصيلاً



ما هي المشاكل مع خادمنا؟

إذا فكرت في الأمر ، فهناك عدد غير قليل!

  • أولاً ، يمكن لخادمنا قبول عميل واحد فقط. إذا أراد العملاء الآخرون الاتصال ، فلا يمكنهم ذلك.
  • بعد ذلك ، نفترض دائمًا أننا ننتظر رسالة من العميل وأن نعيدها فورًا بعد الاستلام. ولكن هذا ليس هو الحال دائمًا: في بعض الأحيان ترسل رسالة إلى العميل عندما لا يكون قد أرسل لك أي شيء ، وأحيانًا تتلقى معلومات منه عندما لا تكون قد أرسلت أي شيء.
استخدم برنامج المراسلة الفورية: هل عليك انتظار محادثك للرد عليك من أجل التحدث؟ ليس الأمر "أنا أرسل رسالة ، يجيبني ، أجيب عليه ، يجيب علي" ... أحيانًا ، غالبًا ، سترسل رسالتين متتاليتين ، ربما حتى ثلاث رسائل ، أو العكس باختصار ، يجب أن نكون قادرين على إرسال عدة رسائل للعميل واستلام عدة رسائل بترتيب غير معروف. مع أسلوبنا ، هذا مستحيل (قم بإجراء الاختبار إذا كنت تريد).

أيضًا ، يتم التعامل مع الأخطاء بشكل سيئ ، ستوافق على ذلك.

الوحدة  select


ستتيح لنا الوحدة Select شيئًا مثيرًا للاهتمام للغاية ، وهو استجواب العديد من العملاء أثناء انتظار تلقي رسالة ، دون شل برنامجنا.

للتخطيط ، select ستستمع إلى قائمة العملاء وتعود بعد وقت محدد. ما تعيده select هو قائمة العملاء الذين لديهم رسالة لتلقيها. فقط تصفح هؤلاء العملاء ، واقرأ الرسائل المعلقة ( بفضل recv ).

على نظام Linux ، select يمكن استخدامها في أي شيء آخر غير المقابس ، ولكن نظرًا لأن هذه الميزة ليست محمولة ، فأنا أذكرها هنا فقط.

نظريا


الوظيفة التي نهتم بها بنفس اسم الوحدة النمطية المرتبطة بها select . يأخذ ثلاث أو أربع وسيطات ويعيد ثلاثة. حان الوقت لتوخي الحذر:

الحجج التي تأخذها الوظيفة هي:

  • rlist  : قائمة المقابس التي تنتظر قراءتها ؛
  • Wlist  : قائمة المقابس التي تنتظر كتابتها ؛
  • xlist  : قائمة المقابس التي تنتظر الخطأ (لن أسهب في هذه القائمة) ؛
  • Timeout : مقدار الوقت الذي تنتظره الوظيفة قبل العودة. إذا حددت مهلة 0، فستعود الوظيفة على الفور. إذا لم يتم تحديد هذه المعلمة ، فستعود الوظيفة بمجرد تغيير حالة أحد المقابس (تكون جاهزة للقراءة إذا كانت موجودة rlist على سبيل المثال) ولكن ليس قبل ذلك.
بشكل ملموس ، سنكون مهتمين بشكل أساسي بالمعامل الأول والرابع. في الواقع، wlist و xlist لا تهمنا في الوقت الحاضر.

ما نريده هو وضع مقابسنا (socket)في قائمة select وجعلها تراقبها ، والعودة بمجرد أن يكون المقبس جاهزًا للقراءة. بهذه الطريقة لا يحظر برنامجنا ويمكنه تلقي رسائل من عدة عملاء بترتيب غير معروف تمامًا.

الآن ، فيما يتعلق بـ timeout : كما أخبرتك ، إذا لم تحددها ، يتم select تعليقها حتى تصبح إحدى المقابس التي نستمع إليها جاهزة للقراءة ، في حالتنا. إذا قمت بتحديد timeout من 0، select فسيعود على الفور. خلاف ذلك ، select سيعود بعد الوقت الذي تحدده بالثواني ، أو قبل ذلك إذا كان المقبس جاهزًا للقراءة.

في الأساس، وإذا وضعت timeout من 1 وظيفة ومنع لمدة تصل إلى الثانية. ولكن إذا كان أحد مقابس الاستماع جاهزًا للقراءة في هذه الأثناء (أي إذا أرسل أحد العملاء رسالة إلى الخادم) ، فستعود الوظيفة قبل الأوان.

Select تُعيد ثلاث قوائم، مرة أخرى rlist ، wlist و xlist ، إلا أن هذه ليست هي قوائم الإدخال ولكن فقط مقابس "لتصبح" في حالة rlist .

انه غير واضح ؟ ضع في اعتبارك هذا السطر (لا تجربه حتى الآن):


rlist, wlist, xlist = select.select(clients_connectes, [], [], 2)
 
ستستمع هذه التعليمات للمآخذ الموجودة في القائمة clients_connectes . سيعود خلال ثانيتين على أبعد تقدير. لكنها ستعود عاجلاً إذا أرسل العميل رسالة. يمكن العثور على قائمة العملاء الذين أرسلوا رسالة في المتغير الخاص بنا rlist . ثم نتصفحه ويمكننا الاتصال recv بكل مآخذ.

إذا لم يكن الأمر أكثر وضوحًا ، فكن مطمئنًا: سنرى select في العمل أكثر قليلاً. يمكنك أيضًا إلقاء نظرة على الوثائق الخاصة بالوحدة المختارة  .

select  عمليا


سنقوم ببعض العمل على خادمنا. يمكنك الاحتفاظ بنفس عميل الاختبار.

سيكون الهدف هو إنشاء خادم يمكنه قبول العديد من العملاء واستلام رسائلهم وإرسال تأكيد لهم في كل استقبال. لا يتغير التمرين كثيرًا ولكننا سنستخدم select للعمل مع العديد من العملاء.

لقد ذكرت select للاستماع إلى العديد من العملاء المتصلين ولكن هذه الوظيفة ستسمح لنا أيضًا بمعرفة ما إذا كان عميل واحد (أو أكثر) متصلاً بالخادم. إذا كنت تتذكر ، فإن الطريقة accept هي أيضًا وظيفة حظر. سنستخدمها بنفس الطريقة المذكورة أعلاه.

أعتقد أنني أعطيتك معلومات نظرية كافية. يجب أن يتحدث الكود الآن:


import socket
import select

hote = ''
port = 12800

connexion_principale = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connexion_principale.bind((hote, port))
connexion_principale.listen(5)
print("الخادم يستمع الآن على المنفذ {}".format(port))

serveur_lance = True
clients_connectes = []
while serveur_lance:
    # سوف نتحقق من أن العملاء الجدد لا يطلبون الاتصال
    # للقراءة main_connection لهذا ، نستمع إلى 
    # ننتظر بحد أقصى 50 مللي ثانية
    connexions_demandees, wlist, xlist = select.select([connexion_principale],
        [], [], 0.05)
    
    for connexion in connexions_demandees:
        connexion_avec_client, infos_connexion = connexion.accept()
        # أضف المقبس المتصل إلى قائمة العملاء
        clients_connectes.append(connexion_avec_client)
    
    # الآن نستمع إلى قائمة العملاء المتصلين
    # (recv)هم العملاء المراد قراءتهم select العملاء الذين تم إرجاعهم بواسطة 
    # ننتظر هناك مرة أخرى 50 مللي ثانية كحد أقصى
    # نرفق المكالمة لتحديد. حدد في كتلة المحاولة
    # في الواقع ، إذا كانت قائمة العملاء المتصلين فارغة ، فهذا استثناء
    # يمكن رفعه
    clients_a_lire = []
    try:
        clients_a_lire, wlist, xlist = select.select(clients_connectes,
                [], [], 0.05)
    except select.error:
        pass
    else:
        # نذهب من خلال قائمة العملاء للقراءة
        for client in clients_a_lire:
            # العميل هو نوع المقبس
            msg_recu = client.recv(1024)
            # قد تتعطل إذا كانت الرسالة تحتوي على أحرف خاصة
            msg_recu = msg_recu.decode()
            print("Reçu {}".format(msg_recu))
            client.send(b"5 / 5")
            if msg_recu == "fin":
                serveur_lance = False

print("إغلاق الاتصالات ")
for client in clients_connectes:
    client.close()

connexion_principale.close()
 
إنه أطول إيه؟ ومع ذلك ، لا مفر منه.

الآن يمكن لخادمنا قبول الاتصالات من أكثر من عميل ، يمكنك اختباره. أيضًا ، لا يتوقف انتظار رسالة ، على الأقل ليس أكثر من 50 مللي ثانية.

أعتقد أن التعليقات محددة بما يكفي لتذهب أبعد من ذلك. هذه بالطبع ليست نسخة كاملة حتى الآن ، ولكن بفضل هذه القاعدة ، يجب أن تكون قادرًا على تحقيق شيء ما بسهولة. لماذا لا تُنشئ دردشة مصغرة؟

كما لا يتم التعامل مع حالات قطع الاتصال العارضة. ولكن لديك عناصر كافية لاختبار خادمنا وتحسينه إذا كنت ترغب في ذلك.

وأكثر من ذلك

كما أخبرتك ، تعد الشبكة موضوعًا ضخمًا ، وحتى تضييقًا على الموضوع الذي اخترته ، سيكون هناك الكثير لعرضه لك.  فقط لا يمكن أن تحل محل الوثائق وحتى إذا كنت تريد معرفة المزيد أدعوكم لإلقاء نظرة على مقابس الصفحة ، تحديد و socketserver  .

توفر الوحدة الأخيرة ، socketserver بديلاً لتحميل تطبيقات الخادم الخاص بك. هناك مآخذ أخرى ، على أي حال: يمكنك استخدام مآخذ التوصيل غير المحظورة (أي ، المقابس التي لا تمنع البرنامج عند استخدام أسلوبها accept أو الطريقة recv ) أو الخيوط لتشغيل أجزاء مختلفة من برنامجك. بالتوازي. لكنني سأدعك توثق نفسك حول هذه الموضوعات إذا كانت تهمك!

باختصار



  • في بنية الشبكة التي رأيناها ، يوجد خادم يمكنه التواصل مع العديد من العملاء .
  • لإنشاء اتصال من جانب الخادم أو العميل ، نستخدم الوحدة النمطية socket وفئة socket هذه الوحدة.
  • للاتصال بخادم ، يستخدم مقبس العميل امتداد connect .
  • للاستماع على منفذ معين ، يستخدم الخادم أولاً الطريقة bind ثم الطريقة listen .
  • لتبادل المعلومات ، تستخدم مقابس العميل والخادم الطرق send و recv .
  • لإغلاق اتصال ، يستخدم الخادم أو مقبس العميل امتداد close .
  • Select يمكن أن تكون الوحدة مفيدة إذا كنت ترغب في إنشاء خادم يمكنه إدارة عدة اتصالات في وقت واحد ؛ ومع ذلك ، هناك آخرون.