الثلاثاء، 5 يوليو 2011

برمجة الشبكات بواسطة البايثون

بسم الله الرحمن الرحيم 

توفر لغة بايثون "python" المكتبة البرمجية socket التي تمكنك من التعامل مع الشبكات أو ما يسمى "low socket programming" التي تمكنك من كتابة برامج تستطيع الأتصال عبر الشبكة .



البداية :

لجميع برامج الشبكة مهما أختلفت لغات برمجتها خطوات متشابهة في برمجة الشبكات و تلخص الصورة التالية الخطوات بالنسبة لبرنامج الخادم "Server" و برنامج العميل "Client" :
سأبدأ الشرح بالخطوة الأولى التي يشترك فيها برنامج الخادم "Server" و العميل "Client", و هي أنشاء القابس "Socket" و أسماء البرتوكولات في لغة البياثون :

socket(address_family,protocol)

    • address_family : طريقة كتابة العناوين الخاصة بالبرنامج وهذه قائمة بالطرق الأكثر أستخدما :
    1. AF_INET   : العناوين الخاصة ببرتوكول IP الأصدارة الرابعة (هذه الطريقة التي سنستخدمها في هذا الدرس) .
    2. AF_INET6 : العناوين الخاصة ببرتوكول IP الأصدارة السادسة.
    3. AF_UNIX   :هذه العناوين خاصة بأنظمة لينكس .
    • protocol : البرتوكول الذي سيتم أستخدامه في الأتصال و القائمة توضح البرتوكولات الشائع أستخدمها :
    1. SOCK_STREAM: برتوكول TCP  .
    2. SOCK_DGRAM : برتوكول UDP  .
    3. SOCK_RAW : القابس الخام يسمح لك ببرمجة برامج تنشأ حزم الأنترنت من الصفر مما يسمح لك بالتحكم بكل ما يتم أرساله (برامج التنصت على الشبكة تستخدم القابس الخام في برمجتها) .

    و الأن بعد أن أصبحت لديك فكرة عن أساسيات القابس "Socket" ألى مثال عملي باللغة البايثون :


    import socket
    sos=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    يقوم السطر الأول بأستدعاء المكتبة socket و يجب كتابة هذا السطر في بداية أي برنامج يستدعي الدوال الخاصة ببرامج الشبكات التي ستعرض في هذا الموضوع , أما السطر الثاني فينشأ قابس بالأسم "sos" يعتمد على البرتوكول IP/TCP (هذا الأسم الذي سيتم التعامل به مع القابس في البرنامج ).

    الأن بعد شرح الخطوة الأولى في برمجة الشبكات في بايثون سنبدأ في الشرح الخطوات الباقية في برمجة الخادم "Server" بأستخدام البرتوكول TCP:

    • bind : سيتم في هذه الخطوة تحديد العنوان الخاص بالخادم "Server" الذي يتم تنفيذ البرنامج عليه (في اغلب البرامج التي ستمر عليك سيكون العنوان "localhost" أو عنوان الأي بي 127.0.0.1 )  , كما يجب أن يقوم المبرمج بتحديد المنفذ الذي سيستقبل البرنامج عليه الأتصالات الواردة من الشبكة.
    sos.bind(("localhost",80))

    تم تحديد المنفذ في هذه المثال بالمنفذ 80 الخاص برتوكول HTTP .

    • listen : البدأ بأنتظار الأتصالات الواردة من الشبكة , تستطيع تحديد عدد الأتصالات المسموح بأستقبالها في نفس الوقت كما في المثال:
    sos.listen(5)

    في المثال سيتم تحديد عدد الأتصالات بخمسة .

    • accept : عند قبول الأتصال يتم الحصول على عنوان الأي بي الخاص بالعميل و أعطاء منفذ محلي (local port) للبرنامج ( يتم أعطاء المنفذ بدون تدخل من المبرمج):
    mysock,(raddr,rport)=sos.accept()

    في بايثون تعيد الطريقة "accept" كائن أو "object" يتم التعامل معه للأرسال و أستقبال البيانات , في مثالنا سيكون "mysock" , كما سيتم أعطاء قيمة الأي بي للعميل "raddr" و المنفذ المحلي "rport".

    • send & recv : تستخدم مع الكائن الذي تنشأه accept للأرسال البيانات و أستقبالها كما في المثال :
    data=mysock.recv(1024)
    mysock.send("<H1>Welcome to my Server</H1>")

    في الأمر "recv" يجب تحديد الذاكرة المستخدمة لحفظ البيانت بالبايت , في المثال تم تحديدها بـ1024 كما أنني في المثال حفظت البيانات المستلمة في المتغير "data" , أما الأمر "send" فيجب فقط أن تحدد البيانات التي يجب أرسالها في القوسين .

    • close : يتم بهذا أنهاء الأتصال بين الخادم و العميل و هذا مثال على أستخدامه :
    sos.close()

    و الأن سوف أعرض برنامج الخادم "Server" بأستخدام برتوكول TCP كامل بعد أن فهمت الكيفية التي يعمل بها :

    import socket
    sos=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sos.bind(("localhost",80))
    sos.listen(5)
    mysock,(raddr,rport)=sos.accept()
    data=mysock.recv(1024)
    mysock.send("<H1>Welcome to my Server</H1>")
    sos.close()

    و الأن ألى شرح برمجة الخادم بأستخدام برتوكول UDP , سيكون البرمجة مشابه للبرتوكول TCP مع أختلاف أنه في برمجة UDP لا يحتاج ألى عملية listen و accept .

    • أنشاء قابس خاص ببرتوكول UDP
    import socket
    sos=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    • bind
    sos.bind(("localhost",2255))

    تلاحظ التشابه بين الخطوات السابقة و برتوكول TCP .

    • أستقبال البيانات من العميل 
    في برامج التي تعتمد على برتوكول UDP لا حاجة ألى listen كما في المثال التالي:

    while 1:
            data,addr = sos.recvfrom(1024)
            print data.strip(),addr

    سنقوم بأنشاء حلقة تكرارية لا يمكن أيقافها ألا بضغط "Ctrl+D" بأستخدام while لكي يتم أستقبال البيانات من قبل العميل :
    while 1:
           

    يتم أستخدام الطريقة البرمجية "recvfrom" للأستلام البيانات في برامج UDP بعد تحديد الحد الأقصى للذاكرة لكل حزمة :
    data,addr = sos.recvfrom(1024)

    تقوم هذا الطريقة البرمجية بحفظ البيانات في المتغير "data" و عنوان المرسل "IP" في المتغير addr , السطر الخير سيقوم بطباعة البيانات , الأن ألى البرنامج كامل :

    import socket
    sos=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    sos.bind(("localhost",2255))
    while 1:
            data,addr = sos.recvfrom(1024)
            print data.strip(),addr

    الأن مع برمجة العميل , طبعا لن أتطرق ألى النقاط المشتركة مع الخادم "Server" بالتفصيل , وسأبدأ ببرمجة عميل ببرتوكول TCP :

    • أنشاء القابس خاص ببرتوكول TCP
    import socket
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    • بدأ الأتصال مع الخادم "Server"
    sock.connect(("example.com",80))

    تحتاج الدالة connect ألى عنوان الموقع أو رقم الأي بي , ثم رقم المنفذ الذي يعمل عليه الخادم الذي يراد الأتصال به .

    • أرسال و أستقبال البيانات 
    sock.send("GET /index.html")
    data=sock.recv(1024)

    تستخدم نفس الأوامر الخاص بالخادم للأرسال و أستقبال البيانات .

    • أغلاق الأتصال 
    sock.close()


    و الأن ألى البرنامج كامل , هذا البرنامج يتصل بالموقع "example.com"  بأستخدام برتوكول HTTP الذي يعمل على المنفذ 80 .
    import socket
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect(("example.com",80))
    sock.send("GET /index.html")
    data=sock.recv(1024)
    sock.close()

    أما برمجة العميل ببرتوكول UDP فيجب كما في الأمثلة السابقة تعريف القابس كالتالي :

    import socket
    sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    • ثم يمكنك أرسال البيانات مباشرة بأستخدام الأمر "sendto" :

    sock.sendto("test", ("example.com", 8111))

    سيتم أرسال البيانات "test" ألى الموقع "example.com" على المنفذ 8111 .
    • أغلاق الأتصال 
    sock.close()

    و هنا البرنامج كاملا :

    import socket
    sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    sock.sendto("test", ("example.com", 8111))
    sock.close()


    في نهاية هذه المقال , يجب أن أنبه أن الأمثلة الموجودة لا يوجد فيها أي ألية للتحقق من أخطاء الأتصال و قد تعمدت هذا لتجنب تعقيد الأمثلة.

    هناك 6 تعليقات:

    1. درس رائع وحلوو ياريت لو في عندك دروس تانية ترسلها لي
      هي اميلي x3d3@hotmail.com تمنى انك تقوم باظافتي
      لاني اقوم ببمرجة تغرات البفر اوفر فلوو باستخدام البايثون

      ردحذف
    2. عندي سؤال و هو عند استبدال ال localhost في العميل بال public ip لا يحدث اتصال و عند البحث عن السبب تبين انه يجب على الراوتر ان يسمح بالاستقبال من البورت المكتوب في البرنامج ... حاولت تغيير اعدادات الراوتر باضافة البورت المطلوب كما اغلقت جدار الحماية في الويندوز ولكن بقي الخطا ذاته.

      الخطا : connection refused by the remote host

      ردحذف
    3. أنا جربت البرنامج بواسطة الأي بي المحلي على نظام لينكس و نجح التنفيذ فتأكد من أعدادات الرواتر و النظام , و أذا ممكن أكتب الكود اللي أستخدمته

      ردحذف
    4. سرح جميل جدا❤❤😍 يارب لو تكملها وتخليها سلسلة جميلة تاخد الامور لمستو اعمق شويه

      ردحذف
    5. هذا الشرح أو هذه البرمجة تشمل للغة python أو هل أستطيع إن أبرمج على للغة python ?

      ردحذف