السلام عليكم ..
طرح موضوع هنا بالمنتدا عن التطبيقات الموزعة والاستدعاء عن بعض وقدم بشكل مشروع لعبة X-O
لذلك احببت ان اتوسع قليلا بالفكرة واشرحها واقدم جزئية منها لكم ..
سوف اتحدث بشكل مختصر عن التطبيقات الموزعة وعن تقنية RMI بشكل عام وكامل
بالبداية سوف أقوم بشرح فكرة عامة عن معنى التطبيقات الموزعة وما تعنيه بالكلمة والمعنى
إن استدعاء الأغراض "object " أو الطرائق أو بعضهم يسمونها المناهج "Method "
إن استدعائها عن بعد يعني ببساطة قيام غرض ما باستدعاء طريقة أو اكثر من غرض اخر موجود على الة جافا وهمية اخرى
نسمي الغرض الاول بالغرض المحلي Local object ونسمي الغرض الثاني بالغرض البعيد Remote object اما التابع أو المنهج أو الطريقة نسميها Remote Method
اما التقنية التي تسمح باستدعاء الطرائق عن بعد فهي RMI (Remote Method Ivocation)
بشكل عام تضم تطبيقات RMI برنامجين منفصلين هما server و client حيث يقوم برنامج المخدم بانشاء بعض الاغراض البعيدة Remote object بالاضافة إلى إمكانية انشاء مراجع أو ما يسما مؤشرات للوصول للاغراض البعيدة وثم يقوم بانتضار الاخ الزبون client وينتظر طلباته .
سنقوم بشرح الية مبسطة عن عمل RMI وحسب ما اعتقده من افكار ..
نستطيع إن نرقم المراحل ..مثلا نقول
اولا يقوم المخدم بانشاء الغرض البعيد ثم يسجله في مسجل RMI والمسجل هوا عبارة عن برنامج خاص ياتي مع حزمة JDK ويعتبر بمثابة قاعدة بيانات
ثانيا يقوم الزبون بالبحث عن الغرض البعيد باستخدام اسمه ومن ثم يحصل على مرجع لهذا الغرض
والذي اسميناه مؤشر على الغرض في ما سبق .
ثالثا يقوم الزبون باستدعاء الطرائق من الغرض البعيد ..
بالاضافة إلى كل ما سبق من خطوات عمل التطبيقات الموزعة الخاصة بالتقنية المذكورة فهي ايضا تعتمد على ما يسمى Stub ,Skeleton
ولن اتكلم شئ عنهم كثير حاليا سيتم استيعابهم في النهاية ولكن ما أريد إن اقوله بشكل مبسط إن كلاهما class فالـ Stub يعمل بجانب الزبون ويقوم بارسال الطلبات للاغراض البعيدة
اما Skeleton يعمل بجانب المخدم ويقوم باستقبال طلبات الزبائن .
بالبداية لكي نقوم بانشاء تطبيق يعتمد على البرمجة الموزعة RMI بالجافا ..علينا إن نضع لانفسنا عدة مخططات ومراحل لكتابة البرنامج ..
*نحتاج إلى تصميم وتحقيق واجهات وصفوف التطبيقات الموزعة " implementation"
*ترجمة الواجهات والصفوف لتوليد Stub ,Skeleton "compilation"
*تحديد سماحيات الاتصال وهي تتعلق بالـport وسماحيات الوصول للـclasses
* تشغيل التطبيق
كل من الخطوات السابقة تشرح نفسها ولكن ما عدا الخطوة الأولى يندرج تحتها عدة خطوات لكن سنفصل كل ما سبق
1-تصميم وتحقيق الواجهات والصفوف
اولا نقوم بتعريف الواجهات interfaces البعيدة ..لماذا هذا ولماذا التفصيل وتعريف كل شئ على حدا
حيث تعتمد هذه التقنية على مبدأ وهوا هام بالنسبة لها مبدأ الفصل بين تعريف الطرائق وبين تحقيقها
وطبعا لكي يكون اسمها تطبيقات موزعة لابد من تحقيق هذا المبدأ وايضا هذه الواجهات تسمى واجهات بعيدة Remote interface
ثانيا تحقيق الاغراض البعيدة
المسؤل عن هذا الشئ أو الصفين الذين يقوما بالمهمة هما
صف اول من قبل المبرمج يقوم من خلاله بتحقيق الخدمة المعرفة في الواجهة البعيدة
صف ثاني وهوا Stub الذي يعمل كوكيل proxy عن الخدمة البعيدة على الجهاز الزبون
وكم ذكرنا إن الزبون يقوم باستدعاء الطريقة البعيدة في المخدم عن طريق هذا class Stub وما يسما proxy ومن ثم تكمل الخطوات المعروفة ..
ثالثا كتابة تطبيق المخدم
بعد الانتهاء من كتابة الصف البعيد ( الصف الذي يحقق الواجهة البعيدة ) يجب كتابة تطبيق المخدم الذي يقوم بإنشاء غرض من الصف البعيد وتسجيل هذا الغرض في مسجل RMI
رابعا كتابة تطبيق الزبون
ايضا يتم كتابة تطبيق الزبون الذي سيقوم بالبحث في مسجل RMI عن الغرض المشتق من الصف البعيد
2- ترجمة الصفوف والواجهات وتوليد صفي Stub , Skeleton
كالعادة بالنسبة للترجمة نستخدم المترجم javac
ولكن نحن بحاجة إلى المترجم rmic لتوليد الصفين المذكورين
3-تحديد سماحيات الاتصال وسماحيات الوصول
مرحلة هامة بعض الشئ وهي تتعلق بالمنافذ ..ستتضح في الكود
4- تشغيل التطبيق
-تشغيل مسجل RMI
- تشغيل المخدم
- تشغيل الزبون
وايضا سوف تتضح فيما بعد .
ألان وبعد كل ما سبق من كلام نظري نحاول إن نطبق اكواد برمجية ونطبق التقنية على برنامج صغير
يقوم بجمع عددين باستخدام تقنية RMI ويجب إن ننتبه لكل الخطوات النظرية السابقة لأننا سنعمل عليها أو على مبدئها
تطبيق جمع عددين :
سألخصه لكم على الشكل التالي:
يتضمن تطبيق المخدم على غرض يحوي طريقة جمع method sum
ونريد من تطبيق الزبون إن يستدعي هذه الطريقة لجمع عددين ومن ثم طباعة النتيجة
اولا نقوم بتصميم الواجهة البعيدة Remote interface
وعلى الواجهة البعيدة إن تتضمن تعريف لجميع الطرائق method التي سيتم استدعاؤها عن بعد من قبل الة الجافا
وحتى تكون الواجهة بعيدة يجب إن تملك الخصائص التالية :
* يجب إن تعرف الواجهة البعيدة باستخدام محددات الوصول public والا فأن الزبون سيحصل على رسالة خطا عند محاولة تحمي الغرض البعيد الذي يحقق الواجهة إلا في حال الزبون موجود في نفس حزمة الواجهة البعيدة
* يجب على الواجهة البعيدة إن ترث الواجهة java.rmi.Remote
* يجب على كل طريقة في الواجهة البعيدة إن ترمي استثناء من نوع java.rmi.RemoteException
اضافة إلى أي استثناء خاصة بالطريقة نفسها ..
*يجب التصريح عن أي غرض بعيد سيمرر كوسيط للطريقة بعيدة أو كقيمة معادة على انه من نمط الواجهة البعيدة وليس من نمط الصف البعيد
فيما يلي الواجهة البعيدة SumRemoteInterface التي تتضمن طريقة واحدة بعيدة هي
sum (int x,int y)
import java.rmi.*;
public interface SumRemoteInterface extends Remote {
public int sum(int x,int y) throws RemoteException;
}
package sum;
سبب رمي الاستثناء للـ method sum هوا بما إن كل طريقة بعيدة معرضة للفشل لعدة اسباب كان لا بد من رمي الاستثناء
ما زلنا في تصميم الصفوف والواجهات البند الاول من خطوات العمل مع هذه التقنية والان سوف نقوم بكتابة الصف البعيد (الذي يقوم بدوره في تحقيق الواجهة interface البعيدة )
ومن خصائص الصف التي يجب إن يحققها
• التصريح على إن هذا الصف يحقق واجهة بعيدة واحدة
• تعريف باني لهذا الصف (والسبب سنذكره لاحقا )
• كتابة تحقيق برمجي للطرائق methods التي سيتم استدعاؤها
import java.rmi.*;
import java.rmi.server.*;
public class SumRemoteClass extends UnicastRemoteObject implements SumRemoteInterface {
public SumRemoteClass() throws RemoteException {
super();
}
public int sum(int x,int y) throws RemoteException{
return x+y;
}
}
package sum;
قام الصف SumRemoteClass بتحقيق الواجهة SumRemoteInterface كما وعد
نتكلم عن بعض النقاط ..
بالبداية سبب استيراد الصف UnicastRemoteObject والتوعدات من ذلك هوا إن الصف المذكور اعلاه يؤمن التواصل مع الزبائن عن طريق استخدام طريقة النقل المعتمدة على المنافذ الافتراضية لتقنية RMI
بالاضافة إلى العمل طوال الوقت بانتضار طلبات الزبائن
سبب ذكر التابع البناء ..كغيره هنا التابع البناء وضيفته مثل وضيفة أي تابع بناء في أي برنامج
بالاضافة يحتاج غرض الصف البعيد إلى تصدير exported حيث يجعله جاهز لقبول طلبات استدعاء method الطرائق المناهج سموها ما تشاؤون ...
عند استيراد الصف UnicastRemoteObject فانها تصبح مصدرة بشكل تلقائي
اذا اضطرينا إن إن نجعل الكلاس SumRemoteClass إن يتوسع من كلاس اخر غير SumRemoteClass
فلا بد إن نذكر يدوي أو نصرح عن استيراد الصف SumRemoteClass في البناء الخاص بالصف
اما بالنسبة لرمي بناء الصف SumRemoteClass استثناء RemoteException
تجنبا لحدوث مشاكل بالاتصال أو قد يكون الاتصال غير متوفر حاليا .
بالاضافة لكل ما سبق اننا قمنا بتحقيق الـطريقة sum وذلك بكتابة جسمها
import java.rmi.*;
public class SumServer {
public static void main (String[] args) {
if(System.getSecurityManager()==null)
{
System.setSecurityManager(new RMISecurityManager());
}
try{
SumRemoteClass sumremoteclass=new SumRemoteClass();
Naming.rebind("//host/SumService",sumremoteclass);
System.out.println("sum server is ready");
}
catch (Exception e)
{
System.out.println("sum server fail: "+ e);
e.printStackTrace();
}
}
}
package sum;
نشرح شوي ..
بالبدية في main لصف المخدم يجب إن نضع البسملة الخاصة في اعداد مدير الحماية وهي
{
System.setSecurityManager(new RMISecurityManager());
}
if(System.getSecurityManager()==null)
داخل حلقة الـ try قمنا بانشاء الغرض من الصف المحقق للواجهة وذلك بهدف توفير الخدمة
كذلك يجب إن نقوم بتسجيل للغرض في مسجل RMI كالكود التالي
Naming.rebind("//host/SumService",sumremoteclass);ماذا يحوي الكود السابق ..
يحوي الصف Naming ويستخدم من اجل تخزين الاغرض البعيدة في مسجل RMI يالاضافة إلى الحصول على مراجع أي مؤشرات كما اسميناها سابقا ..
بالاضافة إلى ما سبق هناك الطريقة bind وقد ذكرتها في اليه عمل RMI
حيث تحوي هذه الطريقة على وسيط اول وهوا URL خاص للوصول إلى للاسم الاختياري للغرض المسجل حيث نذكر بدل كلمة host مثلا اسم الجهاز المحلي أو البعيد
وذا لم نذكر اسم الجهاز صراحة سوف يشير إلى Localhost
اما الوسيط الثاني هوا غرض من الصف البعيد object
ألان نقوم بكتابة صف الزبون
import java.rmi.*;
public class SumClient {
public static void main (String[] args) {
if(System.getSecurityManager()==null)
{
System.setSecurityManager(new RMISecurityManager());
}
try{
SumRemoteInterface sri=(SumRemoteInterface)Naming.lookup("//host/SumService");
System.out.println(sri.sum(3,5));
}
catch (Exception e)
{
System.out.println("SumClient exception :" +e);
}
}
}
package sum;
نلاحظ يقوم الزبون بالبحث عن الغرض البعيد باسم SumService وثم يحصل على مرجع لهذا الغرض وكما نلاحظ الطريقة lookup وهي من اخوات bind و rebind وغيرهم اما الاخيرة وهي خاصة باعادة تسجيل الغرض
اما lookup فهي مهمتها البحث عن الغرض و هناك اخرى صديقتها list وتابعا ايضا للصف Naming
مهمتها الحصول على قائمة باسماء الاغراض البعيدة المسجلة في مسجل RMI
يجب على صيغة URL الممررة للطريقة lookup إن تتضمن اسم المخدم والا فأن خطأ ما سوف يحدث
بشكل عام الية عمل التقنية اصبحت شبه مفهومة ..يوجد الكثير من معلومات ومراحل يجب ان اتكلم عنها كتشغيل التطبيق لتوليد
الصفين Stub , skeleton الذين يولدهما المترجم rmic
ساحاول ان اطرح الطريقة لاحقا ..لكن الى الان تواجهني بعض المشاكل في تشغيل التطبيق
اي استفسارات انا بالخدمة ...طبعا سوف يكون للموضوع بقية ..وساحاول ان اصل في نهايته الى تطبيق اكبر قليلا من الذي تكلمنا عنه سابقا
تمنياتي لكم بالتوفيق
الله معكم ..


