JavaRush /مدونة جافا /Random-AR /RMI: ممارسة الاستخدام

RMI: ممارسة الاستخدام

نشرت في المجموعة
مرحبًا! اليوم سننظر في موضوع مثير للاهتمام إلى حد ما - RMI . هذا يعني استدعاء الطريقة عن بعد . RMI: ممارسة الاستخدام - 1باستخدام RMI، يمكنك تعليم برنامجين التواصل مع بعضهما البعض، حتى لو كانا على أجهزة كمبيوتر مختلفة. يبدو جيدا؟ :) ولكن ليس من الصعب القيام بذلك! في محاضرة اليوم سوف نفهم ما هي الأجزاء التي يتكون منها تفاعل RMI وكيفية تكوينه. أول شيء نحتاجه هو العميل والخادم . ليس عليك التعمق في مصطلحات الكمبيوتر. في حالة RMI، هذان مجرد برنامجين. سيحتوي أحدهما على كائن ما، بينما سيستدعي الثاني أساليب هذا الكائن. استدعاء أساليب كائن في برنامج ما موجود في برنامج آخر - لم نفعل هذا من قبل! حان الوقت لمحاولة ذلك! :) لكي لا نغرق في البراري، فليكن برنامجنا بسيطًا. بشكل عام، تقوم الخوادم عادةً بإجراء بعض العمليات الحسابية التي يطلبها العميل. سيكون هو نفسه بالنسبة لنا. سيكون لدينا برنامج حاسبة بسيط كخادم. سيكون لديها طريقة واحدة فقط - multiply(). سيقوم بضرب الرقمين المرسلين إليه من قبل برنامج العميل وإرجاع النتيجة. أولا نحتاج إلى واجهة:
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
لماذا نحتاج إلى واجهة؟ والحقيقة أن عمل RMI يقوم على إنشاء الوكلاء، وهو ما قمت بدراسته في إحدى المحاضرات السابقة . والعمل مع الوكلاء، كما تتذكر على الأرجح، يتم على وجه التحديد على مستوى الواجهات، وليس على مستوى الفئات. هناك متطلبان مهمان لواجهتنا!
  1. يجب أن يرث واجهة الرمز المميز البعيد.
  2. يجب أن تقوم جميع أساليبها بطرح RemoteException (لا يتم ذلك تلقائيًا في IDE، يجب عليك كتابته يدويًا!).
نحتاج الآن إلى إنشاء فئة خادم يمكنها تنفيذ واجهتنا Calculator. RMI: ممارسة الاستخدام - 2كل شيء هنا بسيط جدًا أيضًا:
import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
ليس هناك الكثير للتعليق عليه هنا :) نحتاج الآن إلى كتابة برنامج خادم يقوم بتكوين وتشغيل فئة حاسبة الخادم الخاصة بنا. سوف يبدو مثل هذا:
import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
دعونا نكتشف ذلك :) في السطر الأول نقوم بإنشاء نوع من متغيرات السلسلة:
public static final String UNIQUE_BINDING_NAME = "server.calculator";
هذه السلسلة هي الاسم الفريد للكائن البعيد . بهذا الاسم، سيتمكن برنامج العميل من العثور على الخادم الخاص بنا: ستشاهد ذلك لاحقًا. بعد ذلك نقوم بإنشاء كائن الآلة الحاسبة لدينا:
final RemoteCalculationServer server = new RemoteCalculationServer();
كل شيء واضح هنا. ما يلي أكثر إثارة للاهتمام:
final Registry registry = LocateRegistry.createRegistry(2732);
هذا الشيء المسمى التسجيل هو سجل للكائنات المحذوفة . "محذوف" ليس بمعنى أننا قمنا بحذفها من الكمبيوتر، ولكن في حقيقة أنه يمكن الوصول إلى الكائنات من هذا السجل عن بعد من برامج أخرى :) LocateRegistry.createRegistry()لقد مررنا الرقم 2732 إلى الطريقة، هذا هو رقم المنفذ. إذا كنت لا تعرف ما هو المنفذ، فيمكنك قراءته هنا ، ولكن في الوقت الحالي عليك فقط أن تتذكر أن هذا رقم فريد يمكن للبرامج الأخرى من خلاله العثور على سجل الكائنات الخاص بنا (سترى هذا أيضًا أدناه). هيا لنذهب. دعونا نرى ما سيحدث في السطر التالي:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
على هذا الخط نقوم بإنشاء كعب . يقوم كعب الروتين بتغليف عملية الاتصال عن بعد بأكملها داخل نفسه. ويمكن القول أن هذا هو العنصر الأكثر أهمية في RMI. ماذا تفعل هي؟
  1. يتلقى جميع المعلومات حول مكالمة عن بعد لطريقة ما.
  2. إذا كانت الطريقة تحتوي على معلمات، فسيقوم كعب الروتين بإلغاء تسلسلها. انتبه لهذه النقطة! يجب أن تكون المعلمات التي تمررها إلى طرق المكالمات عن بعد قابلة للتسلسل (بعد كل شيء، سيتم إرسالها عبر الشبكة). ليس لدينا مثل هذه المشكلة - نحن فقط ننقل الأرقام. ولكن إذا قمت بنقل الأشياء، فلا تنسَ ذلك!
  3. بعد ذلك، فإنه يستدعي الطريقة المطلوبة.
نقوم بتمرير UnicastRemoteObject.exportObject()كائن حاسبة الخادم الخاص بنا إلى الطريقة. بهذه الطريقة نجعل من الممكن استدعاء أساليبها عن بعد. لم يبق لدينا سوى شيء واحد لنفعله:
registry.bind(UNIQUE_BINDING_NAME, stub);
نقوم "بتسجيل" كعب الروتين الخاص بنا في سجل الكائنات البعيدة تحت الاسم الذي توصلنا إليه في البداية. الآن يمكن للعميل العثور عليه! ربما لاحظت أننا في النهاية وضعنا الخيط الرئيسي للبرنامج في وضع السكون:
Thread.sleep(Integer.MAX_VALUE);
نحتاج فقط إلى الحفاظ على تشغيل الخادم لفترة طويلة. سنقوم بتشغيل طريقتين في IDEa في وقت واحد main(): أولاً، الخادم (في الفصل ServerMainالذي كتبناه بالفعل)، ثم العميل (في الفصل الذي ClientMainسنكتبه أدناه). من المهم ألا يتعطل برنامج الخادم أثناء تشغيل العميل، لذلك نقوم ببساطة بوضعه في وضع السكون لفترة طويلة. سيظل يعمل :) الآن يمكننا تشغيل main()طريقة الخادم الخاصة بنا. دعه يعمل وانتظر حتى يستدعي برنامج العميل طريقة ما :) الآن دعنا نكتب برنامج عميل! سيتم إرسال أرقام إلى خادمنا للمضاعفة.
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
انها تبدو غير معقدة. ما الذي يحدث هنا؟ أولاً، يجب أن يكون العميل على علم بالاسم الفريد للكائن الذي سيستدعي أساليبه عن بعد. ولذلك، قمنا أيضًا بإنشاء متغير في برنامج العميل، public static final String UNIQUE_BINDING_NAME = "server.calculator"; وبعد ذلك، في الطريقة، main()يمكننا الوصول إلى سجل الكائنات البعيدة. للقيام بذلك، نحتاج إلى استدعاء الطريقة LocateRegistry.getRegistry()وتمرير رقم المنفذ الذي تم إنشاء السجل الخاص بنا عليه في برنامج ServerMain - المنفذ 2732 (تم اختيار هذا الرقم على سبيل المثال، يمكنك تجربة استخدام رقم آخر):
final Registry registry = LocateRegistry.getRegistry(2732);
الآن كل ما علينا فعله هو الحصول على الكائن المطلوب من السجل! إنه أمر سهل لأننا نعرف اسمه الفريد!
Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
انتبه إلى نوع الصب. لقد قمنا بإلقاء الكائن الناتج على واجهة Calculatorبدلاً من فئة محددة RemoteCalculationServer . كما قلنا في بداية المحاضرة، يعتمد RMI على استخدام الوكيل، لذا فإن الاتصال عن بعد متاح فقط لطرق الواجهات، وليس للفئات. في النهاية، نستدعي طريقة multiply()على كائننا عن بعد ونطبع النتيجة على وحدة التحكم.
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
لقد أطلقنا الطريقة main()في الفصل ServerMainمنذ وقت طويل، وحان الوقت لإطلاق الطريقة main()في برنامج العميل ClientMain! إخراج وحدة التحكم: 600 هذا كل شيء! لقد أدى برنامجنا (حتى اثنان!) وظيفته بنجاح :) إذا كان لديك الوقت والرغبة، فيمكنك تنويعها قليلاً. على سبيل المثال، تأكد من أن الآلة الحاسبة تدعم جميع العمليات القياسية الأربع، وليس الأرقام، ولكن يتم تمرير كائن كمعلمات CalculationInstance(int x, int y). كمواد إضافية، يمكنك إلقاء نظرة على المقالات والأمثلة - هنا: نراكم في الفصول القادمة! :)
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION