كيف تعمل البرامج التي تعتمد على الشبكات

البرمجة الشبكية تعد محورا أساسيا في عالم البرمجة. و يمكن للمستعمل العادي أن يلاحظ أصنافا عديدة من البرامج التي تعتمد على هذا الصنف من البرمجة مثل الألعاب الشبكية, الخوادم التي تعتمد على قواعد البيانات database servers و برامج أخرى لا تعد و لا تحصى نذكر منها برامج المحادثة و المتصفحات...
في هذا المقال سنتعرض للمبدأ العام التي تعتمد عليه هذه البرامج, و من ثم سنوضح ما قلناه من خلال مثال تجريبي باستعمال لغة البرمجة Python.






1. رسم توضيحي لكيفية عمل الشبكة

من المعلوم أنه يوجد بروتكلين أساسيين لتبادل المعلومات على مستوى الشبكات TCP  و UDP, و هما يختلفان في عدة نقاط من بينها طريقة التواصل بين السرفر و ال client.

نستعرض في البداية المراحل التي يمر بها الطلب بين ال server و client بالنسبة لل TCP:
نجد أن server دائما ما يبدأ في العمل أولا و يكون مستعدا لأي طلب يقدمه client, بعد دخول client على الشبكة سيحاول الإتصال بال server لفتح اتصال بينهما ()connect, و عند وصول الطلب سيقوم server بقبول طلب client عندما يكون مستعدا لذلك أي عندما لا يسبقه client آخر في فتح اتصال. بعد فتح اتصال يبدأ الطرفان في تبادل المعلومات فيما بينهما, و ينتهي في الأخير بإغلاق الإتصال بين الطرفين ()close.

أما عند استخدام بروتوكول UDP فالعملية أبسط من سابقتها حيث لا نجد الثلاثي bind, listen, accept
بل server يتلقى الطلب من client و يقوم بالرد عليه.

كما تلاحظون العملية برمتها سهلة, و لكننا لتبسيط الأمور قمنا بتجاوز الحديث عن عنصر هام للغاية و بدونه لا يتم الإتصال
 ألا و هو socket.
و يمكن تعريف ال socket أو ما يعبر عنه بالعربية بالمقبس بأنه  قناة اتصال تربط بين جهازين ( حاسوبين ) و يتم الاتصال عبر المنفذ أو بما يعبر عنه ( البورت = Port ) و الاي بي ( IP يعني اي بي الجهاز ) بهدف تبادل المعطيات بينهما.

2. تعريف socket من الجانب البرمجي:

تحتاج الsocket لكي تعمل إلى ثلاث عناصر Arguments 
  • المجال/النطاق domain لتحديد العائلة التي ينتمي إليها البروتوكول مثال ذلك نجد 
PF_INET يستعمل لبرتوكول الشبكة IPv4
PF_INET6 لل IPv6
PF_UNIX لل socket المحلي(عبر الملفات)
  • النوع type و يكون أحد الأنواع التالية:
 SOCK_STREAM
    Stream Sockets
SOCK_DGRAM
SOCK_SEQPACKET
SOCK_RAW
  • البروتوكول protocol 
و أكثرها شيوعا
IPPROTO_TCP, IPPROTO_SCTP, IPPROTO_UDP, IPPROTO_DCCP

و بذلك يكون الشكل العام لل socket كالتالي:

int socket(int domain, int type, int protocol);
 من جانب آخر يرتبط bind بال socket لإعطائه عنوان IP .

3. تطبيقيا:

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


لتطبيق ما جاء في الفيديو ستحتاج لتثبيت package التالي:

sudo apt-get install python-ipy
ثم سننشأ ملفين الأول خاص بالسرفر:

#!/usr/bin/python
from IPy import IP
import socket

myip = socket.gethostbyname(socket.gethostname())
ipinfo = "IP => %s\nVersion => %s\nType =>  %s\nNetmask => %s\nBrodacast =>\
%s\nHex => %s\nBinary => %s\nLookup => %s\n" % (IP(myip), IP(myip).version(),\
IP(myip).iptype(), IP(myip).netmask(), IP(myip).broadcast(), IP(myip).strHex(),\
IP(myip).strBin(), IP(myip).reverseNames())
sck = socket.socket()
sck.bind((socket.gethostname(), 1234))
sck.listen(5)
while True:
  c, addr = sck.accept()
  print "Connected from: ", addr
  c.send(str(ipinfo))
  c.close()
في البداية ننسخ هذه الأسطر في ملف نسميه على سبيل المثال server.py, , نقوم بتشغيله بالشكل التالي:
python server.py

و نتركه يعمل من دون أن نغلقه.

في الملف الثاني client.py انسخ الأسطر التالية:

#!/usr/bin/python
import socket

sck = socket.socket()
sck.connect((socket.gethostname(),1234))
print sck.recv(1024)
sck.close()
بعد تشغيل الملف الثاني سنحصل على النتيجة التالية:

IP => 127.0.1.1
Version => 4
Type =>  PRIVATE
Netmask => 255.255.255.255
Brodacast =>127.0.1.1
Hex => 0x7f000101
Binary => 01111111000000000000000100000001
Lookup => ['1.1.0.127.in-addr.arpa.']

كما لاحظتم كل ما ذكرناه في بداية الشرح تعرضنا إليه مجددا:

قمنا في البداية بإنشاء socket 
sck = socket.socket()
 ثم في ال bind قمنا بتحديد ip و port الذي سنستعمله.
sck.bind((socket.gethostname(), 1234))

و يبدأ في الإنصات
 sck.listen(5)
 و عند وصول الطلب يقبله و يعمل على تنفيذه

while True:
  c, addr = sck.accept()
  print "Connected from: ", addr

ثم يقوم بمعالجة المعطيات التي يطلبها منه client حيث من الممكن أن تكون مثلا مجرد عملية حسابية بسيطة و لكنها في هذه الحال فلدينا طلب address ip 

 myip = socket.gethostbyname(socket.gethostname())
ipinfo = "IP => %s\nVersion => %s\nType =>  %s\nNetmask => %s\nBrodacast =>\
%s\nHex => %s\nBinary => %s\nLookup => %s\n" % (IP(myip), IP(myip).version(),\
IP(myip).iptype(), IP(myip).netmask(), IP(myip).broadcast(), IP(myip).strHex(),\
IP(myip).strBin(), IP(myip).reverseNames())

ليقوم server بعد معالجتها بإعادة إرسالها
 c.send(str(ipinfo))
و في اﻷخير يغلق الإتصال:
  c.close()

أرجو أن تكونو قد استفدتم