วันพุธที่ 29 เมษายน พ.ศ. 2558

Java RMI ตอนที่ 2: การเขียนโปรแกรมฝั่งเซิร์ฟเวอร์

หลังจากเข้าใจว่าจาวาอาร์เอ็มไอ (Java RMI) คืออะไรแล้วจากตอนที่ 1 ในตอนนี้เราจะเริ่มมาพัฒนาโปรแกรมกันครับ โดยเราจะเริ่มจากฝั่งเซิร์ฟเวอร์กันก่อน โดยเราจะต้องคิดว่าอ็อบเจกต์ที่เราจะพัฒนาขึ้นจะให้บริการอะไรบ้าง โดยเราจะต้องเขียนรายการแอ็บแสตรกท์เมท็อด (abstract method) ที่จะให้บริการข้ามเครื่องในรูปแบบอินเทอร์เฟซ (interface) และไม่ใช่อินเทอร์เฟซธรรมดาจะต้องเป็นอินเทอร์เฟซระยะไกล (remote interface) ด้วย การประกาศอินเทอร์เฟซระยะไกลทำได้ง่ายมากด้วยการใช้รูปแบบการประกาศอินเทอร์เฟซของจาวาตามปกติ แต่ให้อินเทอร์เฟซนั้นเอ็กซ์เทนด์ (extend) อินเทอร์เฟซที่จาวาเตรียมไว้ให้แล้วที่ชื่อว่า Remote สรุปก็คือรูปแบบการประกาศอินเทอร์เฟซระยะไกลมีรูปแบบดังนี้

interface <interface name> extends Remote {...}

ไม่เอาดีกว่าอธิบายแบบนี้อาจไม่เข้าใจ มาดูตัวอย่างกันดีกว่า สมมติเราจะสร้างอ็อบเจกต์ที่จะให้บริการขึ้นมาสักตัวหนึ่ง เราจะสร้างอะไรกันดีครับ เอา Hello Wolrd ดีไหม... ไม่ดีนะครับน่าเบื่อ เอาอย่างนี้แล้วกันสร้างอ็อบเจกต์ที่ให้บริการบวกลบเลขดีไหมครับ น่าเบื่อน้อยลงหน่อย เอาตามนี้นะครับ มาสร้างกันเลย จากอ็อบเจกต์ที่เราต้องการสามารถสร้างอินเทอร์เฟซระยะไกลได้ดังนี้

1 import java.rmi.Remote;
2 import java.rmi.RemoteException;
3 interface MyMath extends Remote {
  public int add(int num1, int num2) throws RemoteException;
  public int subtract(int num1, int num2) throws RemoteException;
6 }


จากโค้ดตัวอย่างก็คือเราสร้างอินเทอร์เฟซระยะไกลชื่อ MyMath ซึ่งมีแอ็บสแตรกท์เมท็อดสองตัวคือ add() และ subtract() ให้สังเกตว่าแต่ละเมท็อดที่เราจะให้ถูกเรียกใช้จากระยะไกลได้จะต้องโทรว์ (throw) เอ็กซ์เซปชัน (Exception) ที่ชื่อว่า RemoteException

ตอนนี้เราจะเริ่มสร้างคลาสกันครับ ซึ่งคลาสที่เราจะสร้างบนฝั่งเซิร์ฟเวอร์นี้เรามักจะสร้างแบ่งเป็นสองคลาสครับ คือคลาสที่เรียกว่าคลาสผู้รับใช้ (servant class) และคลาสผู้บริการ (server class) คลาสผู้รับใช้เป็นคลาสที่เราอิมพลีเมนต์อินเทอร์เฟซ หรือพูดง่าย ๆ ก็คือมันเป็นคลาสที่สร้างอ็อบเจกต์ที่จะถูกเรียกใช้จากไคลเอนต์ นี่คือเหตุผลที่เราเรียกมันว่าคลาสผู้รับใช้ นอกจากนี้สตับและสเกเลตันจะถูกสร้างจากคลาสนี้เช่นกัน ส่วนคลาสผู้บริการจะเป็นคลาสที่ใช้ในการลงทะเบียนคลาสผู้รับใช้เข้ากับอาร์เอ็มไอรีจีสตรี (RMI Registry) เอาละครับมาเขียนคลาสผู้รับใช้กันดีกว่า

 1 import java.rmi.RemoteException;
 2 import java.rmi.server.UnicastRemoteObject;
 3 public class MyMathImpl extends UnicastRemoteObject implements MyMath  {
 4    public MyMathImpl() throws RemoteException {
 5      super();
 6    }
 7    public int add(int num1, int num2) throws RemoteException  {
 8       return num1+num2;
 9    }
10    public int subtract(int num1, int num2)throws RemoteException {
11       return num1-num2;
12    }
13
14
}

ข้อสังเกตสำหรับคลาสนี้มีสามเรื่องครับ เรื่องแรกก็คือชื่อของคลาส (บรรทัดที่ 3) นักเขียนโปรแกรมที่พัฒนาจาวาอาร์เอ็มไอนิยมตั้งกันคือคลาสจะมีชื่อเดียวกับอินเทอร์เฟซตามด้วย Impl จากโปรแกรมที่เรากำลังพัฒนาอินเทอร์เฟซของเรามีชื่อว่า MyMath ดังนั้นเราจึงตั้งชื่อคลาสนี้ว่า MyMathImpl เรื่องที่สองก็คือคลาสนี้สืบทอดคุณสมบัติมาจากคลาส UnicastRemoteObject ซึ่งเป็นคลาสที่จาวาเตรียมเอาไว้เพื่อสนับสนุนการเรียกอ็อบเจกต์ข้ามเครื่อง เรื่องที่สามก็คือเราต้องมีคอนสตรักเตอร์ (constructor) ที่โทรว์ RemoteException และเรียกคอนสตรักเตอร์ของคลาส UnicastRemoteObject เอาละครับเรียบร้อยครับ เห็นไหมครับว่าง่ายมาก

[หลังจากเราเขียนคลาสผู้รับใช้เสร็จแล้วเราก็คอมไพล์เพื่อให้ได้ MyMathImpl.class ครับ ถ้าเราใช้จาวาก่อนเวอร์ชัน 5 เราก็ใช้คำสั่งนี้ในการสร้างสตับและสเกเลตันได้เลยครับ

rmic MyMathImpl

เราจะได้ไฟล์ชื่อ MyMathImpl_Stub.class ซึ่งไฟล์นี้จะทำหน้าที่เป็นทั้งสตับและสเกเลตัน 

ซึ่งผมว่าตอนนี้เราคงไม่ใช้ภาษาจาวาเก่าแบบนั้นแล้วนะครับ ดังนั้นถ้าใครใช้ Java 5  ขึ้นมาก็ข้ามไปได้เลยนะครับ เพราะในจาวารุ่นใหม่จาวารันไทม์ (Java Runtime) จะจัดการเรื่อง Stub-Skeleton ให้

]

คราวนี้มาดูคลาสผู้ให้บริการกัน

 1 import java.net.*;
 2 import java.rmi.*;
 3 import java.rmi.registry.Registry;
 4 import java.rmi.registry.LocateRegistry;
 5 public class MyMathServer 
 6 {
 7    public static void main(String[] args)
 8    {
 9      
10       try
11       {
12          MyMathImpl myMathObj = new MyMathImpl();
13          Registry registry = LocateRegistry.getRegistry();
14          registry.bind("MyMathServer", myMathObj);
15          System.out.println("MyMath Server ready");
16       }
17       catch (Exception re) {
18          System.out.println("Execption in MyMathServer: " + re);
19       }
20    }
21 }

จากโปรแกรมจะเห็นว่าเราสร้างอ็อบเจกต์เรฟเฟอร์เรนซ์ (object referennce) ของคลาส MyMathImpl ในบรรทัดที่ 12 จากนั้นบรรทัดที่ 13 ประโยค

Registry registry = LocateRegistry.getRegistry();

เป็นการค้นหาอาร์เอ็มไอรีจิสตรีที่รันอยู่ในระบบ นั่นหมายความว่าก่อนจะรันโปรแกรมเซิร์ฟเวอร์เราต้องรันอาร์เอ็มไอรีจิสตรีก่อนซึ่งจะรันยังไงนั้นจะอยู่ในตอนต่อไปครับ บรรทัดที่ 14 ประโยค

 registry.bind("MyMathServer", myMathObj);

เป็นการลงทะะเบียนอ็อบเจกต์เรฟเฟอร์เรนซ์ดังกล่าวในชื่อ MyMathServer ซึ่งโปรแกรมฝั่งไคลเอนต์ที่เราจะเขียนในตอนต่อไปจะค้นหาอ็อบเจกต์นี้โดยใช้ชื่อนี้

เอาล่ะครับตอนนี้เราก็เสร็จงานด้านเซิร์ฟเวอร์แล้ว ตอนต่อไปเราจะไปเขียนไคลเอนต์ แล้วก็ลองรันกันดูครับ โปรดอดใจสักนิดหนึ่งนะครับ ขอพักหน่อย ถ้าใครไม่อยากพิมพ์โปรแกรมเองสามารถดาวน์โหลดโค้ดได้จาก Github ครับ 


ไม่มีความคิดเห็น:

แสดงความคิดเห็น