JavaRush /จาวาบล็อก /Random-TH /RMI: การปฏิบัติในการใช้งาน

RMI: การปฏิบัติในการใช้งาน

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะดูหัวข้อที่ค่อนข้างน่าสนใจ- RMI สิ่งนี้ย่อมาจากRemote Method Invocation 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 ขึ้นอยู่กับการสร้างผู้รับมอบฉันทะซึ่งคุณศึกษาในการบรรยายครั้งก่อน และการทำงานกับพรอกซีอย่างที่คุณคงจำได้นั้นดำเนินการในระดับอินเทอร์เฟซอย่างแม่นยำไม่ใช่คลาส มีข้อกำหนดที่สำคัญ 2 ประการสำหรับอินเทอร์เฟซของเรา!
  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);
สิ่งนี้เรียกว่า Registry คือรีจิสทรีของวัตถุที่ถูกลบ แต่ในความเป็นจริงแล้ววัตถุจากการลงทะเบียนนี้สามารถเข้าถึงได้จากระยะไกลจากโปรแกรมอื่น :) LocateRegistry.createRegistry()เราส่งหมายเลข 2732 ไปยังเมธอด นี่คือหมายเลขพอร์ต หากคุณไม่ทราบว่าพอร์ตคืออะไร คุณสามารถอ่านได้ที่นี่แต่ตอนนี้คุณเพียงแค่ต้องจำไว้ว่านี่คือหมายเลขเฉพาะที่โปรแกรมอื่นสามารถค้นหารีจิสตรีอ็อบเจ็กต์ของเราได้ (คุณจะเห็นสิ่งนี้ด้านล่างด้วย) เดินหน้าต่อไป มาดูกันว่าเกิดอะไรขึ้นในบรรทัดถัดไป:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
ในบรรทัดนี้เราสร้าง ต้นขั้ว stubสรุปกระบวนการโทรระยะไกลทั้งหมดไว้ภายในตัวมันเอง อาจกล่าวได้ว่านี่คือองค์ประกอบที่สำคัญที่สุดของ RMI เธอกำลังทำอะไรอยู่?
  1. รับข้อมูลทั้งหมดเกี่ยวกับการเรียกเมธอดระยะไกล
  2. หากวิธีการมีพารามิเตอร์ stub จะทำการดีซีเรียลไลซ์พวกมัน ให้ความสนใจจุดนี้! พารามิเตอร์ที่คุณส่งไปยังวิธีการโทรระยะไกลจะต้องทำให้เป็นอนุกรมได้ (หลังจากนั้นพารามิเตอร์จะถูกส่งผ่านเครือข่าย) เราไม่มีปัญหาดังกล่าว - เราแค่ส่งหมายเลขเท่านั้น แต่ถ้าคุณถ่ายโอนวัตถุอย่าลืมมัน!
  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