ওহে! আজ আমরা একটি বরং আকর্ষণীয় বিষয় বিবেচনা করব: Java RMI। এর অর্থ হল রিমোট মেথড ইনভোকেশন। আপনি দুটি প্রোগ্রাম একে অপরের সাথে যোগাযোগ করার অনুমতি দিতে RMI ব্যবহার করতে পারেন, এমনকি যদি তারা বিভিন্ন কম্পিউটারে থাকে। যে শান্ত শব্দ? :) এবং এটি করা এত কঠিন নয়! আজকের পাঠে, আমরা RMI ইন্টারঅ্যাকশনের উপাদানগুলি বিশ্লেষণ করব এবং কীভাবে এটি কনফিগার করতে হয় তা বের করব। আমাদের প্রথম জিনিসটি একটি ক্লায়েন্ট এবং একটি সার্ভার প্রয়োজন। আমাদের আসলে কম্পিউটার পরিভাষায় গভীরভাবে ডুব দেওয়ার দরকার নেই। যখন এটি আরএমআই আসে, এই দুটি প্রোগ্রাম মাত্র। তাদের মধ্যে একটি একটি বস্তু অন্তর্ভুক্ত করবে, এবং অন্যটি সেই বস্তুর পদ্ধতিগুলিকে কল করবে। একটি ভিন্ন প্রোগ্রামে বিদ্যমান একটি বস্তুর কলিং পদ্ধতি - এখন এটি এমন কিছু যা আমরা এখনও করিনি! এটা চেষ্টা করার সময়! :) আটকা পড়া এড়াতে, আসুন' আমাদের প্রোগ্রাম সহজ রাখুন. সাধারণভাবে, একটি সার্ভার কিছু গণনা করে যা একটি ক্লায়েন্ট দ্বারা অনুরোধ করা হয়। এবং তাই এটি আমাদের সাথে হবে. আমাদের সার্ভার একটি সাধারণ ক্যালকুলেটর প্রোগ্রাম হবে. এটি শুধুমাত্র একটি পদ্ধতি থাকবে:গুণ () । এটি ক্লায়েন্ট প্রোগ্রাম দ্বারা প্রেরিত দুটি সংখ্যাকে গুণ করবে এবং তারপর ফলাফলটি ফেরত দেবে। প্রথমত, আমাদের একটি ইন্টারফেস প্রয়োজন:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Calculator extends Remote {
int multiply(int x, int y) throws RemoteException;
}
কেন আমরা একটি ইন্টারফেস প্রয়োজন? কারণ RMI প্রক্সি তৈরির উপর নির্ভর করে, যা আপনি অতীতের পাঠে অধ্যয়ন করেছেন । আপনি সম্ভবত মনে রাখবেন, আমরা ক্লাস নয়, ইন্টারফেসের মাধ্যমে প্রক্সিগুলির সাথে কাজ করি। আমাদের ইন্টারফেসের জন্য 2টি গুরুত্বপূর্ণ প্রয়োজনীয়তা রয়েছে!
- এটি রিমোট ইন্টারফেস প্রসারিত করতে হবে।
- এর সমস্ত পদ্ধতি অবশ্যই একটি RemoteException নিক্ষেপ করবে (IDE স্বয়ংক্রিয়ভাবে এটি করবে না - আপনাকে এটি ম্যানুয়ালি যোগ করতে হবে!)
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 এর সবচেয়ে গুরুত্বপূর্ণ উপাদান বিবেচনা করতে পারেন। এটার কাজ কি?
- এটি কোনও পদ্ধতির দূরবর্তী কল সম্পর্কে সমস্ত তথ্য গ্রহণ করে।
- পদ্ধতিতে পরামিতি থাকলে, স্টাব সেগুলিকে ডিসিরিয়ালাইজ করবে। এই বিন্দু মনোযোগ দিতে! আপনি যে আর্গুমেন্টগুলিকে রিমোটলি বলা পদ্ধতিতে পাস করেন সেগুলি অবশ্যই সিরিয়ালাইজেবল হতে হবে (সর্বশেষে, সেগুলি নেটওয়ার্কের মাধ্যমে প্রেরণ করা হবে)। এটি আমাদের জন্য কোন সমস্যা নয় - আমরা শুধু সংখ্যা প্রেরণ করছি। কিন্তু যদি আপনি বস্তু প্রেরণ করছেন, এই প্রয়োজনীয়তা ভুলবেন না!
- এর পরে, স্টাবটি পছন্দসই পদ্ধতিকে কল করে।
registry.bind(UNIQUE_BINDING_NAME, stub);
আমরা আমাদের স্টাবটিকে রিমোট অবজেক্ট রেজিস্ট্রিতে "রেজিস্টার" করি যার নামে আমরা একেবারে শুরুতে তৈরি করেছি। এখন ক্লায়েন্ট এটি খুঁজে পেতে সক্ষম হবে! সম্ভবত আপনি লক্ষ্য করেছেন যে আমরা প্রোগ্রামের মূল থ্রেডটিকে শেষ পর্যন্ত ঘুমাতে রেখেছি:
Thread.sleep(Integer.MAX_VALUE);
দীর্ঘ সময় ধরে চালানোর জন্য আমাদের শুধু সার্ভার দরকার। IDE-তে, আমরা একই সাথে দুটি main() পদ্ধতি চালু করব: প্রথম, সার্ভারের main() পদ্ধতি (ServerMain ক্লাসে , যা আমরা ইতিমধ্যে লিখেছি), এবং দ্বিতীয়, ক্লায়েন্টের main() পদ্ধতি (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);
}
}
এটা সহজ দেখায়. কিন্তু এখানে কি হচ্ছে? প্রথমত, ক্লায়েন্টকে অবশ্যই অবজেক্টের অনন্য নাম জানতে হবে যার পদ্ধতিগুলি এটি দূর থেকে কল করবে। সেই অনুযায়ী, ক্লায়েন্ট প্রোগ্রামে, আমরা পাবলিক স্ট্যাটিক ফাইনাল স্ট্রিং UNIQUE_BINDING_NAME = "server.calculator" তৈরি করেছি; পরিবর্তনশীল এরপর, main() পদ্ধতিতে, আমরা দূরবর্তী বস্তুর রেজিস্টারে অ্যাক্সেস পাই। এটি করার জন্য, আমাদের LocateRegistry.getRegistry() পদ্ধতিতে কল করতে হবে এবং সার্ভারমেইন প্রোগ্রামে আমাদের রেজিস্ট্রি তৈরি করতে ব্যবহৃত পোর্ট নম্বরটি পাস করতে হবে (পোর্ট 2732; এই নম্বরটি শুধুমাত্র একটি উদাহরণ — আপনি একটি ভিন্ন নম্বর ব্যবহার করে দেখতে পারেন):
final Registry registry = LocateRegistry.getRegistry(2732);
এখন আমাদের শুধু রেজিস্ট্রি থেকে কাঙ্খিত বস্তুটি পেতে হবে! এটি সহজ, কারণ আমরা এর অনন্য নাম জানি!
Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
টাইপ কাস্টিং মনোযোগ দিন. আমরা প্রাপ্ত বস্তুটিকে ক্যালকুলেটর ইন্টারফেসে নিক্ষেপ করি, রিমোট ক্যালকুলেশন সার্ভার ক্লাসে নয় । যেমনটি আমরা পাঠের শুরুতে বলেছি, RMI একটি প্রক্সির উপর নির্ভর করে, তাই দূরবর্তী কলগুলি শুধুমাত্র একটি ইন্টারফেসের পদ্ধতির জন্য উপলব্ধ, একটি ক্লাসের পদ্ধতি নয়। অবশেষে, আমরা দূরবর্তীভাবে আমাদের অবজেক্টে multiply() পদ্ধতিটিকে কল করি এবং ফলাফলটি কনসোলে আউটপুট করি।
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
সার্ভারমেইন ক্লাসের main () পদ্ধতিটি ইতিমধ্যেই দীর্ঘদিন ধরে চলছে। এখন ক্লায়েন্ট প্রোগ্রাম ( ClientMain ) এ main() পদ্ধতি চালানোর সময় ! কনসোল আউটপুট:
600
এটাই! আমাদের প্রোগ্রাম (দুটি প্রোগ্রাম, আসলে!) যা করার কথা ছিল তা করেছে :) আপনার যদি সময় এবং ইচ্ছা থাকে তবে আপনি এটিকে কিছুটা মশলা করতে পারেন। উদাহরণস্বরূপ, ক্যালকুলেটরটিকে চারটি স্ট্যান্ডার্ড গাণিতিক ক্রিয়াকলাপ সমর্থন করুন এবং সংখ্যাগুলিকে আদিম প্রকার হিসাবে নয়, বরং ক্যালকুলেশন ইনস্ট্যান্স (int x, int y) অবজেক্ট হিসাবে পাস করুন৷ পরবর্তী পাঠে দেখা হবে! :)
GO TO FULL VERSION