John Squirrels
سطح
San Francisco

جاوا RMI

گروپ میں شائع ہوا۔
ہائے! آج ہم ایک دلچسپ موضوع پر غور کریں گے: Java RMI۔ اس کا مطلب ریموٹ میتھڈ انووکیشن ہے۔ آپ دو پروگراموں کو ایک دوسرے کے ساتھ بات چیت کرنے کی اجازت دینے کے لیے 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. اسے ریموٹ انٹرفیس کو بڑھانا چاہیے۔
  2. اس کے تمام طریقوں کو ایک RemoteException پھینکنا ضروری ہے (IDE یہ خود بخود نہیں کرے گا - آپ کو اسے دستی طور پر شامل کرنے کی ضرورت ہے!)
اب ہمیں ایک سرور کلاس بنانے کی ضرورت ہے جو ہمارے کیلکولیٹر انٹرفیس کو نافذ کرے۔ عملی طور پر 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. اگر طریقہ میں پیرامیٹرز ہیں، تو اسٹب ان کو ڈی سیریلائز کر دے گا۔ اس نکتے پر توجہ دیں! جو دلائل آپ دور دراز سے کہلائے گئے طریقوں پر منتقل کرتے ہیں وہ سیریلائز ہونے چاہئیں (آخر کار، وہ نیٹ ورک پر منتقل کیے جائیں گے)۔ یہ ہمارے لیے کوئی مسئلہ نہیں ہے - ہم صرف نمبرز منتقل کر رہے ہیں۔ لیکن اگر آپ اشیاء کو منتقل کر رہے ہیں، تو اس ضرورت کو مت بھولنا!
  3. اس کے بعد، سٹب مطلوبہ طریقہ کو کال کرتا ہے.
ہم اپنے کیلکولیٹر سرور آبجیکٹ کو UnicastRemoteObject.exportObject() طریقہ پر منتقل کرتے ہیں۔ اس طرح ہم اس کے طریقوں کو دور سے کال کرنا ممکن بناتے ہیں۔ بس ایک کام باقی ہے:
registry.bind(UNIQUE_BINDING_NAME, stub);
ہم اپنے اسٹب کو ریموٹ آبجیکٹ رجسٹری میں اس نام سے "رجسٹر" کرتے ہیں جو ہم نے شروع میں بنایا تھا۔ اب کلائنٹ اسے تلاش کرنے کے قابل ہو جائے گا! شاید آپ نے دیکھا ہو کہ ہم نے پروگرام کے مرکزی دھاگے کو آخر میں سونے کے لیے رکھ دیا ہے:
Thread.sleep(Integer.MAX_VALUE);
ہمیں لمبے عرصے تک چلانے کے لیے سرور کی ضرورت ہے۔ IDE میں، ہم بیک وقت دو مین () طریقے شروع کریں گے: پہلا، سرور کا مین() طریقہ ( ServerMain کلاس میں، جسے ہم پہلے ہی لکھ چکے ہیں)، اور دوسرا، کلائنٹ کا main() طریقہ (ClientMain کلاس میں ، جسے ہم ذیل میں لکھیں گے)۔ یہ ضروری ہے کہ جب ہم کلائنٹ کو شروع کرتے ہیں تو سرور پروگرام کو ختم نہ کیا جائے، اس لیے ہم اسے کافی دیر تک سونے کے لیے رکھتے ہیں۔ کسی بھی صورت میں، یہ چلتا رہے گا :) اب ہم اپنے سرور کا مین() طریقہ چلا سکتے ہیں۔ اسے چلنے دیں اور کلائنٹ پروگرام کا کچھ طریقہ کال کرنے کا انتظار کریں :) اب کلائنٹ پروگرام لکھتے ہیں! یہ ہمارے سرور کو ضرب کے لیے نمبر بھیجے گا۔
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);
ٹائپ کاسٹنگ پر توجہ دیں۔ ہم موصول شدہ اعتراض کو کیلکولیٹر انٹرفیس پر ڈالتے ہیں، نہ کہ RemoteCalculationServer کلاس میں۔ جیسا کہ ہم نے سبق کے آغاز میں کہا، RMI ایک پراکسی پر انحصار کرتا ہے، اس لیے ریموٹ کالز صرف انٹرفیس کے طریقوں کے لیے دستیاب ہیں، کلاسز کے طریقوں کے لیے نہیں۔ آخر میں، ہم اپنے آبجیکٹ پر multiply() طریقہ کو دور سے کال کرتے ہیں اور نتیجہ کو کنسول میں آؤٹ پٹ کرتے ہیں۔
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
ServerMain کلاس کا main() طریقہ پہلے ہی کافی عرصے سے چل رہا ہے ۔ اب کلائنٹ پروگرام ( ClientMain ) میں main() طریقہ چلانے کا وقت آگیا ہے ! کنسول آؤٹ پٹ:

600
یہی ہے! ہمارے پروگرام (دو پروگرام، اصل میں!) نے وہی کیا جو اسے کرنا چاہیے تھا :) اگر آپ کے پاس وقت اور خواہش ہے، تو آپ اس میں تھوڑا سا اضافہ کر سکتے ہیں۔ مثال کے طور پر، کیلکولیٹر کو چار معیاری ریاضی کی کارروائیوں کا سہارا بنائیں، اور نمبروں کو ابتدائی اقسام کے طور پر نہیں، بلکہ کیلکولیشن انسٹینس (int x، int y) اشیاء کے طور پر پاس کریں۔ اگلے سبق میں ملتے ہیں! :)
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION