كنت أتجول في بعض مواقع البرمجة الأجنبية فوجدت موضوعاً جميلاً عن فحص المنافذ الفعالة بواسطة الدالة GetTcpTable
أحببت أن أترجم لكم الدرس لتعم الفائدة ولكني خلال الترجمة وجدت أن الموضوع يحتاج لشرح أكثر فأحببت صياغة الموضوع من جديد ليكون انفع بإذن الله .
والآن ننتقل للدرس :
دوال الـ IP Helper API كثيرة و تزودنا بفوائد حول الشبكات (الحرفين IP هما اختصار للكلمتين Internet Protocol)
فمثلاً الوظيفة GetTcpTable تعطي معلومات عن جميع إتصالات البروتوكول TCP الفعالة .
فقط باستدعاء واحد للوظيفة السابقة ستحصل على جدول فيه حالة المنفذ و رقم المنافذ الفتوحة لهذا الاتصال و رقم الأيبي للطرفين .
ومع هذا لا تظن أن استخدام الوظيفة GetTcpTable إلى هذا الحد من البساطة :) سنحاول أن نأخذ مثال عملي يوضح لنا كيفية عمل هذه الدالة ثم ننتقل للوثائق ليكون عملنا موثق :) .
للإعلان عن الدالة GetTcpTable نكتب السطر التالي :
Declare Function GetTcpTable Lib "iphlpapi.dll" (ByRef pTcpTable As PMIB_TCPTABLE, _ ByRef pdwSize As Long, _ ByVal bOrder As Long) As Long
و منه يتضح لنا أن الدالة لها 3 بارامترات (وسائط) :
الأول : جدول الاتصالات الفعالة من نوع MIB_TCPTABLE
الثاني : حجم جدول الاتصالات الفعالة من نوع Long
الثالث: فرز الجدول من نوع Long
والآن أول خطوة هي الحصول على حجم البيانات في جدول اتصالاتTCP . نمرر للدالة البارامترات التالية :
الأول : 0
الثاني : رقم طويل من نوع Long
الثالث : 0
كالتلي :
Dim lngSize, lngRetVal As Long lngRetVal = GetTcpTable(ByVal 0&, lngSize, 0)
والآن بعد تنفيذ الدالة السابقة سنحصل على معلومتين :
الأولى : حجم البيانات في جدول اتصالات TCP و يوضع في المتغير lngSize
الثانية : نتيجة العملية وتوضع في المتغير lngRetVal وهي تدل على نجاح العملية أو سبب فشلها .
هذه الثوابت هي تحليل للقيمة المعادة من الدالة :
Const ERROR_BUFFER_OVERFLOW = 111& Const ERROR_INVALID_PARAMETER = 87 Const ERROR_NO_DATA = 232& Const ERROR_NOT_SUPPORTED = 50& Const ERROR_SUCCESS = 0&
والآن و بعد أن حصلنا على حجم بيانات الجدول TCP
و تأكدنا من نجاح العملية و أن النظام يدعم الـ IP Helper API
نلقي نظرة على وثائق مايكروسوفت عن الدالة GetTcpTable
DWORD GetTcpTable( PMIB_TCPTABLE pTcpTable, // buffer for the connection table PDWORD pdwSize, // size of the buffer BOOL bOrder // sort the table? );
الكود السابق ييشرح لنا بنية الدالة GetTcpTable ونلاحظ أن الوسيط الأول من نوع PMIB_TCPTABLE .
هذه التركيبة (MIB_TCPTABLE) وكما في الوثائق فإن لها البنية التالية :
typedef struct _MIB_TCPTABLE {
DWORD dwNumEntries; // number of entries in the table
MIB_TCPROW table[ANY_SIZE]; // array of TCP connections
} MIB_TCPTABLE, *PMIB_TCPTABLE;وهنا نتوقف عند نقطتين :
النقطة الأولى :
توجد تركيبة أخرى إضافية وهي MIB_TCPROW و بنيتها كالتالي :
typedef struct _MIB_TCPROW {
DWORD dwState; // state of the connection
DWORD dwLocalAddr; // address on local computer
DWORD dwLocalPort; // port number on local computer
DWORD dwRemoteAddr; // address on remote computer
DWORD dwRemotePort; // port number on remote computer
} MIB_TCPROW, *PMIB_TCPROW;و النقطة الثانية :
أن التركيبة MIB_TCPTABLE تحوي على عضوين :
1- dwNumEntries وهو من نوع Long وهذا لا إشكال فيه .
2- table[ANY_SIZE] وهو مصفوفة تركيبة من نوع MIB_TCPROW ، وهنا يقع الإشكال لمبرمجي الفيجوال بيسك .
وهو كيف سيتم الإعلان عن تركيبة (MIB_TCPTABLE) تحتوي على تركيبة (MIB_TCPROW) على شكل مصفوفة "متغيرة" ؟
في هذا الموضع لا تستطيع فيجوال بيسك أن تكون بمرونة C++ ولكن يمكن الإلتفاف على هذه النقطة بأن نحدد طول المصفوفة بـ 500 مثلاً أي 500 صف اتصال وهذا سقف لا اظن أن أي جهاز سيفتح اتصالات بهذا الكم . مع أني وجدت في بعض مواقع البرمجة الأجنبية من يحدد هذا العدد بـ 100 إتصال فقط . و اظنه كاف .
المهم ، نستطيع أن نحاكي تراكيب الـ C++ :) بالإعلان عن التركيبتين التاليتين :
Const MAX_ROW As Integer = 500 Private Type MIB_TCPROW dwState As Long dwLocalAddr As Long dwLocalPort As Long dwRemoteAddr As Long dwRemotePort As Long End Type Private Type MIB_TCPTABLE dwNumEntries As Long ' number of entries in the table table(MAX_ROW) As MIB_TCPROW ' array of TCP connections End Type
لو كان إعلان التركيبة الثانية بهذا الشكل لأصدر لن االمصرف خطأ :
Private Type MIB_TCPTABLE dwNumEntries As Long ' number of entries in the table table() As MIB_TCPROW ' array of TCP connections End Type
والسبب هو أننا لم نحدد طول مصفوفة الـ MIB_TCPROW :
عموماً بهذا الإلتفاف نستطيع أن نعلن عن متغير من نوع MIB_TCPTABLE ونمرره كوسيط أول للدالة GetTcpTable التي ستضف فيها بيانات الاتصالات TCP الفعالة . على النحو التالي :
Dim tcpTable As MIB_TCPTABLE lngRetVal = GetTcpTable(tcpTable, lngSize, 0) )
كما أسلفنا فإن الوسيط الثاني و الذي هو lngSize يعبر عن حجم البيانات في الجدول ، وقد حصلنا عليه من استدعاء سابق لهذه الدالة .
إلى هنا نكتفي و سيكون لنا تكملة في القريب بإذن واحد أحد .
والسلام عليكم ورحمة الله وبركاته


