البرمجة الشبكية تعد محورا أساسيا في عالم البرمجة. و يمكن للمستعمل العادي أن يلاحظ أصنافا عديدة من البرامج التي تعتمد على هذا الصنف من البرمجة مثل الألعاب الشبكية, الخوادم التي تعتمد على قواعد البيانات 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 يستعمل لبرتوكول الشبكة IPv4PF_INET6 لل IPv6PF_UNIX لل socket المحلي(عبر الملفات)
- النوع type و يكون أحد الأنواع التالية:
SOCK_STREAMStream SocketsSOCK_DGRAMSOCK_SEQPACKETSOCK_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()
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()
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.']
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
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())
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()
أرجو أن تكونو قد استفدتم