John Squirrels
مرحله
San Francisco

جاوا RMI

در گروه منتشر شد
سلام! امروز یک موضوع نسبتاً جالب را در نظر خواهیم گرفت: Java RMI. این مخفف Remote Method Invocation است. می توانید از 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 بر ایجاد پراکسی‌هایی است که در درس‌های گذشته مطالعه کرده‌اید . همانطور که احتمالاً به خاطر دارید، ما با پروکسی ها از طریق رابط ها کار می کنیم، نه کلاس ها. 2 الزامات مهم برای رابط ما وجود دارد!
  1. باید رابط Remote را گسترش دهد.
  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);

   }
}
بیایید این را بفهمیم :) در خط اول، مقداری از متغیر String را اعلام می کنیم:
public static final String UNIQUE_BINDING_NAME = "server.calculator";
این رشته نام منحصر به فرد شیء راه دور است. برنامه مشتری ما از این نام برای یافتن سرور ما استفاده می کند: بعداً این را خواهید دید. بعد، ما شیء ماشین حساب خود را ایجاد می کنیم:
final RemoteCalculationServer server = new RemoteCalculationServer();
اینجا همه چیز روشن است. آنچه در ادامه می آید جالب تر است:
final Registry registry = LocateRegistry.createRegistry(2732);
این شی رجیستری یک رجیستری از اشیاء راه دور است. اینها اشیایی هستند که سایر برنامه ها می توانند از راه دور به آنها دسترسی داشته باشند :) ما عدد 2732 را به متد LocateRegistry.createRegistry() منتقل کردیم . این شماره پورت است — یک شماره منحصر به فرد که سایر برنامه ها از آن برای یافتن رجیستری شی ما استفاده می کنند (دوباره، این را در زیر مشاهده خواهید کرد). حرکت درست در امتداد... بیایید ببینیم در خط بعدی چه اتفاقی می افتد:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
در این خط یک خرد ایجاد می کنیم. یک خرد کل تماس از راه دور را در بر می گیرد. شما می توانید این را مهمترین عنصر RMI در نظر بگیرید. چه کار میکند؟
  1. تمام اطلاعات مربوط به تماس از راه دور برخی از روش ها را دریافت می کند.
  2. اگر متد دارای پارامترهایی باشد، stub آنها را از حالت سریال خارج می کند. به این نکته توجه کنید! آرگومان هایی که به متدهایی که از راه دور نامیده می شوند منتقل می کنید باید سریال شوند (در نهایت آنها از طریق شبکه منتقل می شوند). این مشکلی برای ما نیست - ما فقط اعداد را ارسال می کنیم. اما اگر در حال انتقال اشیا هستید، این الزام را فراموش نکنید!
  3. پس از آن، خرد متد مورد نظر را فراخوانی می کند.
ما شیء سرور ماشین حساب خود را به متد UnicastRemoteObject.exportObject() منتقل می کنیم . به این ترتیب ما فراخوانی روش های آن را از راه دور ممکن می کنیم. فقط یک کار باقی مانده است:
registry.bind(UNIQUE_BINDING_NAME, stub);
ما خرد خود را در رجیستری اشیاء راه دور با نامی که در همان ابتدا ساخته بودیم "ثبت می کنیم". اکنون مشتری می تواند آن را پیدا کند! شاید متوجه شده باشید که ما تاپیک اصلی برنامه را در پایان به حالت خوابیده ایم:
Thread.sleep(Integer.MAX_VALUE);
ما فقط نیاز داریم که سرور برای مدت طولانی اجرا شود. در IDE، ما به طور همزمان دو متد main() را راه اندازی می کنیم : اول، متد main() سرور (در کلاس ServerMain که قبلاً نوشته ایم)، و دوم، متد main() کلاینت (در کلاس ClientMain ، که در ادامه خواهیم نوشت). مهم است که برنامه سرور در هنگام راه اندازی کلاینت خاتمه نیابد، بنابراین فقط آن را برای مدت طولانی در حالت Sleep قرار می دهیم. در هر صورت، به کار خود ادامه می دهد :) حالا می توانیم متد 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);
   }
}
ساده به نظر می رسد. اما اینجا چه خبر است؟ ابتدا، مشتری باید نام منحصر به فرد شیئی را که متدهای آن را از راه دور فراخوانی می کند، بداند. بر این اساس، در برنامه مشتری، رشته نهایی ثابت عمومی 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