المتابعون للمدونة

الأحد، 2 يوليو 2017

ملاحظات برمجية في البرنامج IPScanner


ملاحظات برمجية في البرنامج IPScanner:
هذا البرنامج يقوم بفحص الشبكة والحصول على عناوين الأجهزة المتصلة بها.. يمكن تحميله من هنا (توجد نسختان من المشروع إحداهما بلغة سي شارب والأخرى بلغة فيجوال بيزيك دوت نت):

1- مشكلة تجاوز البرنامج حد الذاكرة Memory Overflow بسبب زيادة عدد العمليات الفرعية Threads المتزامنة فوق حد معين:
الفئة PingThread التي تتم العملية الفرعية من خلالها لا تستهلك مساحة كبيرة من الذاكرة، ولكن العمليات الفرعية نفسها تستهلك جزءا من موارد النظام بسبب توزيع وقت التنفيذ بينها، وبالتالي كلما زاد عددها صار تنفيذها أبطأ فتتراكم في الذاكرة دون أن ينتهي أي منها من مهمته، إلى أن تتجاوز المساحة المسموح بها لإطار العمل.. بالتجربة استطعت تشغيل 1000 عملية فرعية متزامنة، لكن الأكثر أمانا أن تكتفي بتشغيل 100 عملية فرعية متزامنة كحد أقصى.. لفعل هذا أضفت شرطا قبل هذا السطر الذي يبدأ تشغيل العملية الفرعية:
th.Start();
هذا الشرط يفحص عدد العمليات الفرعية التي تعمل حاليا، فإن كان أكبر من 100 يعطل تنفيذ الكود لمئة مللي ثانية ثم يعيد فحص الشرط مجددا في حلقة تكرار إلى أن تقل عدد العمليات الفرعية الجارية عن 100، هنا فقط يمكن بدأ عملية فرعية جديدة:
while (TotalIps - scannedIps.Count > 100)
      Thread.Sleep(100); 

TotalIps += 1;
th.Start();
لاحظ أن TotalIps هو متغير يحمل عدد العمليات الفرعية التي تم إطلاقها (تزيد قيمته بواحد عند إطلاق كل عملية فرعية جديدة)، أما القائمة scannedIps فهي تحمل عناوين IP التي تم فحصها بالفعل، وهذا معناه أن العمليات الفرعية التي تفحص هذه العناوين قد انتهى تنفيذها بالفعل.. لهذا لو طرحنا عدد عناصر هذه القائمة من المتغير TotalIps، فسنحصل على عدد العمليات الفرعية التي ما زالت قيد التنفيذ حاليا.
لاحظ أن الوسيلة Thread.Sleep توقف تنفيذ العملية الفرعية الحالية (التي تستدعي هذه الوسيلة).. في حالتنا هذه ستكون هي العملية الفرعية الرئيسية للبرنامج والمسئولة عن تفاعل واجهة البرنامج مع المستخدم.. لهذا قمت بتعطيل التنفيذ لمدة 100 مللي ثانية فقط.. عشرات العمليات الفرعية ستنتهي في هذا الوقت، فهو زمن طويل بالنسبة للحاسوب الذي ينفذ مليارات التعليمات في الثانية.. ولو لم يكن هذا الوقت كافيا فستتكفل حلقة التكرار while بالأمر لمدة 100 مللي ثانية أخرى، وهكذا.. هذا سيجعل أكبر تضييع محتمل للوقت (الانتظار بلا داعٍ)  أقل من 100 مللي ثانية. 

2- مشكلة الحصول على أسماء الأجهزة المتصلة:
للحصول على الاسم اتبعت الخطوات التالية:

الخطوة الأولى:
محاولة الحصول على الاسم باستخدام الوسيلة DNS.GetHostEntry.. ستعيد هذه الوسيلة اسم الجهاز إلا في حالتين:
1-  إذا كان هذا الجهاز راوتر أو آكسيس بوينت.. في الغالب ستعيد هذه الوسيلة في هذه الحالة نفس رقم الـ IP المرسل إليها وليس اسم الجهاز.
2-  إذا كان هذا الجهاز موجودا في شبكة محلية لا تسمح خيارات الآكسيس بوينت الخاص بها بمعرفة أسماء الأجهزة (يحدث هذا مثلا مع بعض أجهزة TPLink مثل الأجهزة من الطراز  TL-WR840N). 

الخطوة الثانية:
إذا فشلت الخطوة الأولى في الحصول على الاسم، فسأفترض أن هذا عنوان IP خاص براوتر أو آكسيس بوينت.. أبسط طريقة للحصول على معلومات عن مثل هذه الأجهزة هي فتح صفحة الإعدادات الخاصة بها.. تذكر أنك تدخل صفحة الإعدادات بكتابة عنوان الـ IP في المتصفح على الصيغة http://[IP] مثل:
http://10.0.0.1
ولفتح صفحة الإعدادات برمجيا، استخدمت الفئة WebClient.. هناك مشكلة صغيرة في هذه الفئة، وهي أنك لا تستطيع التحكم في وقت الانتظار Timeout الخاص بها، لهذا ستعمل بصورة طبيعية مع عناوين الراوتر والأكسيس بوينت، لكن عندما تستخدمها للاتصال بعنوان لا يخص هذه الأجهزة (ليست له صفحة إعدادات) فسيتعطل تنفيذ البرنامج حوالي نصف دقيقة إلى أن تعلن هذه الفئة فشلها!.. لحل هذه المشكلة استخدمت الوراثة لإنشاء فئة جديدة مشتقة من هذه الفئة (اسمها أيضا WebClient لكن كل فئة منهما موجودة في نطاق Namespace مختلف لهذا لن يحدث تضارب)، وأضفت لها خاصية وقت الانتظار بحيث أستطيع تقليل زمن الانتظار إلى ثانية واحدة بدلا من 30 ثانية!
ولكن كيف نحصل على اسم الجهاز من صفحة الإعدادات؟
هناك حالتان:
1-  بعض الأجهزة تعرض صفحة ويب فيها خانة اسم المستخدم وخانة كلمة السر، ويظهر اسم الجهاز (نوع الطراز) كعنوان لهذه الصفحة (على شريط المتصفح).. أنت تعرف أن عنوان صفحة HTML يوجد داخل التاج:
2- بعض الأجهزة لا تعرض صفحة تسجيل الدخول، وإنما تتوقع أن تستقبل اسم المستخدم وكلمة السر ضمن استعلام الويب المرسل إليها، وفي هذه الحالة سيحدث خطأ في البرنامج من النوع WebException حيث ستحتوي الخاصة WebException.Response على كائن الاستجابة الذي يحمل تفاصيل هذا الخطأ.. من خصائص هذا الكائن الخاصية Headers، ويمكننا قراءة قيمة المفتاح Headers["WWW-Authenticate"] حيث سيحتوي على معلومات عن نوع الجهاز على الصيغة:
Basic realm="X"
حيث X هي المعلومات المطلوبة، وسنستخدمها كأنها اسم للجهاز مثل:
TP-LINK Wireless N Access Point WA701ND 

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

بهذه الطريقة سيظهر اسم لكل جهاز على الشبكة تقريبا.. الاستثناء الوحيد هو عناوين الـ IP المستخدمة في أجهزة آكسيس بوينت الخاصة بالتوزيع اللاسلكي Wireless Routers فهذه الأجهزة تربط بين شبكتين، ولا يمكنك أن تدخل صفحة إعدادات الآكسيس بوينت عن طريق عنوانه في الشبكة الخارجية.. لهذا سيظهر هذا العنوان بدون اسم (مثل العنوان رقم 4 في الصورة).. في أغلب الأحوال ستكون مثل هذه العناوين ثابتة لا تتغير كل مرة، لهذا يمكنك أن تكتب بجوارها ملاحظة لتمييزها.
يمكن إدخال ملاحظة بضغط الخانة في العمود Note والكتابة.. أو ضغط أي صف بزر الفأرة الأيمن وضغط الأمر Add A Note من القائمة الموضعية أو ضغط Ctrl+N من لوحة المفاتيح.

 

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

إرسال تعليق

ملحوظة: يمكن لأعضاء المدونة فقط إرسال تعليق.

صفحة الشاعر